Add experimental clang code-model plug-in.

Previously known as the wip/clang branch.

Contributors (in alphabetical order):
- Christian Kamm <christian.d.kamm@nokia.com>
- Erik Verbruggen <erik.verbruggen@digia.com>
- Leandro Melo <leandro.melo@nokia.com>
- Peter Kuemmel <syntheticpp@gmx.net>
- Sergey Shambir <sergey.shambir.auto@gmail.com>

Change-Id: I4c3ff600a19b6732641c1d5ef28236bf2cc17737
Reviewed-by: hjk <hjk121@nokiamail.com>
This commit is contained in:
Erik Verbruggen
2013-12-10 14:37:32 +01:00
committed by hjk
parent 93b7528431
commit 5beb74fd9d
95 changed files with 13289 additions and 3 deletions

View File

@@ -0,0 +1,60 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#define QT_NO_META_MACROS
#define signals public __attribute__((annotate("qt_signal")))
#define slots __attribute__((annotate("qt_slot")))
#define Q_SIGNALS signals
#define Q_SLOTS slots
#define Q_SIGNAL __attribute__((annotate("qt_signal")))
#define Q_SLOT __attribute__((annotate("qt_slot")))
# define Q_PRIVATE_SLOT(d, signature)
#define Q_EMIT
#define emit
#define Q_CLASSINFO(name, value)
#define Q_PLUGIN_METADATA(x)
#define Q_INTERFACES(x)
#define Q_PROPERTY(text)
#define Q_PRIVATE_PROPERTY(d, text)
#define Q_REVISION(v)
#define Q_OVERRIDE(text)
#define Q_ENUMS(x)
#define Q_FLAGS(x)
#define Q_SCRIPTABLE
#define Q_INVOKABLE
#define Q_GADGET \
public: \
static const QMetaObject staticMetaObject; \
private:
#define SIGNAL(a) #a
#define SLOT(a) #a

View File

@@ -38,7 +38,8 @@ DATA_DIRS = \
qml \
qml-type-descriptions \
generic-highlighter \
glsl
glsl \
cplusplus
macx: DATA_DIRS += scripts
for(data_dir, DATA_DIRS) {

View File

@@ -0,0 +1,21 @@
<plugin name=\"ClangCodeModel\" version=\"$$QTCREATOR_VERSION\" compatVersion=\"$$QTCREATOR_VERSION\" experimental=\"true\">
<vendor>Digia Plc</vendor>
<copyright>(C) 2013 Digia Plc</copyright>
<license>
Commercial Usage
Licensees holding valid Qt Commercial licenses may use this plugin in accordance with the Qt Commercial License Agreement provided with the Software or, alternatively, in accordance with the terms contained in a written agreement between you and Nokia.
GNU Lesser General Public License Usage
Alternatively, this plugin may be used under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation. Please review the following information to ensure the GNU Lesser General Public License version 2.1 requirements will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
</license>
<category>C++</category>
<description>Clang Code Model plugin.</description>
<url>http://www.qt-project.org</url>
<dependencyList>
<dependency name=\"Core\" version=\"$$QTCREATOR_VERSION\"/>
<dependency name=\"CppTools\" version=\"$$QTCREATOR_VERSION\"/>
<dependency name=\"TextEditor\" version=\"$$QTCREATOR_VERSION\"/>
</dependencyList>
</plugin>

View File

@@ -0,0 +1,42 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef CLANG_GLOBAL_H
#define CLANG_GLOBAL_H
#include <qglobal.h>
#if defined(CLANGCODEMODEL_LIBRARY)
# define CLANG_EXPORT Q_DECL_EXPORT
#else
# define CLANG_EXPORT Q_DECL_IMPORT
#endif
#endif // CLANG_GLOBAL_H

View File

@@ -0,0 +1,74 @@
isEmpty(LLVM_INSTALL_DIR):LLVM_INSTALL_DIR=$$(LLVM_INSTALL_DIR)
DEFINES += CLANG_COMPLETION
DEFINES += CLANG_HIGHLIGHTING
#DEFINES += CLANG_INDEXING
defineReplace(findLLVMConfig) {
LLVM_CONFIG_VARIANTS = \
llvm-config llvm-config-3.2 llvm-config-3.3 llvm-config-3.4 \
llvm-config-3.5 llvm-config-3.6 llvm-config-4.0 llvm-config-4.1
ENV_PATH = $$(PATH)
win32 {
ENV_PATH = $$split($$ENV_PATH, ;)
} else {
ENV_PATH = $$split($$ENV_PATH, :)
}
for (variant, LLVM_CONFIG_VARIANTS) {
!isEmpty(LLVM_INSTALL_DIR) {
variant=$$LLVM_INSTALL_DIR/bin/$$variant
exists($$variant) {
return($$variant)
}
} else {
for (path, ENV_PATH) {
subvariant = $$path/$$variant
exists($$subvariant) {
return($$subvariant)
}
}
}
}
return(llvm-config)
}
win32 {
LLVM_INCLUDEPATH = $$LLVM_INSTALL_DIR/include
LLVM_LIBS = -L$$LLVM_INSTALL_DIR/bin \
-L$$LLVM_INSTALL_DIR/lib \
-lclang
LLVM_LIBS += -ladvapi32 -lshell32
}
unix {
LLVM_CONFIG = $$findLLVMConfig()
LLVM_INCLUDEPATH = $$system($$LLVM_CONFIG --includedir)
isEmpty(LLVM_INCLUDEPATH):LLVM_INCLUDEPATH=$$LLVM_INSTALL_DIR/include
LLVM_LIBDIR = $$system($$LLVM_CONFIG --libdir)
isEmpty(LLVM_LIBDIR):LLVM_LIBDIR=$$LLVM_INSTALL_DIR/lib
exists ($${LLVM_LIBDIR}/libclang.*) {
#message("LLVM was build with autotools")
CLANG_LIB = clang
} else {
exists ($${LLVM_LIBDIR}/liblibclang.*) {
#message("LLVM was build with CMake")
CLANG_LIB = libclang
} else {
exists ($${LLVM_INSTALL_DIR}/lib/libclang.*) {
#message("libclang placed separately from LLVM")
CLANG_LIB = clang
LLVM_LIBDIR = $${LLVM_INSTALL_DIR}/lib
LLVM_INCLUDEPATH=$${LLVM_INSTALL_DIR}/include
} else {
error("Cannot find Clang shared library!")
}
}
}
LLVM_LIBS = -L$${LLVM_LIBDIR}
LLVM_LIBS += -l$${CLANG_LIB}
}

View File

@@ -0,0 +1,124 @@
include(../../qtcreatorplugin.pri)
include(clang_installation.pri)
message("Building with Clang from $$LLVM_INSTALL_DIR")
LIBS += $$LLVM_LIBS
INCLUDEPATH += $$LLVM_INCLUDEPATH
DEFINES += CLANGCODEMODEL_LIBRARY
unix:QMAKE_LFLAGS += -Wl,-rpath,\'$$LLVM_LIBDIR\'
contains(DEFINES, CLANG_COMPLETION) {
HEADERS += clangcompletion.h clangcompleter.h completionproposalsbuilder.h
SOURCES += clangcompletion.cpp clangcompleter.cpp completionproposalsbuilder.cpp
}
contains(DEFINES, CLANG_HIGHLIGHTING) {
HEADERS += cppcreatemarkers.h clanghighlightingsupport.h
SOURCES += cppcreatemarkers.cpp clanghighlightingsupport.cpp
}
HEADERS += clangutils.h \
cxprettyprinter.h
SOURCES += clangutils.cpp \
cxprettyprinter.cpp
SOURCES += \
$$PWD/clangcodemodelplugin.cpp \
$$PWD/sourcemarker.cpp \
$$PWD/symbol.cpp \
$$PWD/sourcelocation.cpp \
$$PWD/unit.cpp \
$$PWD/utils.cpp \
$$PWD/utils_p.cpp \
$$PWD/liveunitsmanager.cpp \
$$PWD/semanticmarker.cpp \
$$PWD/diagnostic.cpp \
$$PWD/unsavedfiledata.cpp \
$$PWD/fastindexer.cpp \
$$PWD/pchinfo.cpp \
$$PWD/pchmanager.cpp \
$$PWD/clangprojectsettings.cpp \
$$PWD/clangprojectsettingspropertiespage.cpp \
$$PWD/raii/scopedclangoptions.cpp \
$$PWD/clangmodelmanagersupport.cpp
HEADERS += \
$$PWD/clangcodemodelplugin.h \
$$PWD/clang_global.h \
$$PWD/sourcemarker.h \
$$PWD/constants.h \
$$PWD/symbol.h \
$$PWD/cxraii.h \
$$PWD/sourcelocation.h \
$$PWD/unit.h \
$$PWD/utils.h \
$$PWD/utils_p.h \
$$PWD/liveunitsmanager.h \
$$PWD/semanticmarker.h \
$$PWD/diagnostic.h \
$$PWD/unsavedfiledata.h \
$$PWD/fastindexer.h \
$$PWD/pchinfo.h \
$$PWD/pchmanager.h \
$$PWD/clangprojectsettings.h \
$$PWD/clangprojectsettingspropertiespage.h \
$$PWD/raii/scopedclangoptions.h \
$$PWD/clangmodelmanagersupport.h
contains(DEFINES, CLANG_INDEXING) {
HEADERS += \
$$PWD/clangindexer.h \
$$PWD/clangsymbolsearcher.h \
$$PWD/index.h \
$$PWD/indexer.h
# $$PWD/dependencygraph.h \
SOURCES += \
$$PWD/clangindexer.cpp \
$$PWD/clangsymbolsearcher.cpp \
$$PWD/index.cpp \
$$PWD/indexer.cpp
# $$PWD/dependencygraph.cpp \
}
equals(TEST, 1) {
RESOURCES += \
$$PWD/test/clang_tests_database.qrc
HEADERS += \
$$PWD/test/completiontesthelper.h
SOURCES += \
$$PWD/test/completiontesthelper.cpp \
$$PWD/test/clangcompletion_test.cpp
OTHER_FILES += \
$$PWD/test/cxx_regression_1.cpp \
$$PWD/test/cxx_regression_2.cpp \
$$PWD/test/cxx_regression_3.cpp \
$$PWD/test/cxx_regression_4.cpp \
$$PWD/test/cxx_regression_5.cpp \
$$PWD/test/cxx_regression_6.cpp \
$$PWD/test/cxx_regression_7.cpp \
$$PWD/test/cxx_regression_8.cpp \
$$PWD/test/cxx_regression_9.cpp \
$$PWD/test/cxx_snippets_1.cpp \
$$PWD/test/cxx_snippets_2.cpp \
$$PWD/test/cxx_snippets_3.cpp \
test/cxx_snippets_4.cpp \
test/objc_messages_1.mm \
test/objc_messages_2.mm \
test/objc_messages_3.mm
}
FORMS += $$PWD/clangprojectsettingspropertiespage.ui
macx {
LIBCLANG_VERSION=3.3
POSTL = install_name_tool -change "@executable_path/../lib/libclang.$${LIBCLANG_VERSION}.dylib" "$$LLVM_INSTALL_DIR/lib/libclang.$${LIBCLANG_VERSION}.dylib" "\"$${DESTDIR}/lib$${TARGET}.dylib\"" $$escape_expand(\\n\\t)
!isEmpty(QMAKE_POST_LINK):QMAKE_POST_LINK = $$escape_expand(\\n\\t)$$QMAKE_POST_LINK
QMAKE_POST_LINK = $$POSTL $$QMAKE_POST_LINK
}

View File

@@ -0,0 +1,7 @@
QTC_PLUGIN_NAME = ClangCodeModel
QTC_LIB_DEPENDS += \
utils
QTC_PLUGIN_DEPENDS += \
coreplugin \
cpptools \
texteditor

View File

@@ -0,0 +1,96 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "clangcodemodelplugin.h"
#include "clangprojectsettingspropertiespage.h"
#include "fastindexer.h"
#include "pchmanager.h"
#include "utils.h"
#include <coreplugin/coreconstants.h>
#include <coreplugin/icore.h>
#include <coreplugin/imode.h>
#include <coreplugin/modemanager.h>
#include <coreplugin/id.h>
#include <cpptools/cppmodelmanager.h>
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/session.h>
#include <QtPlugin>
namespace ClangCodeModel {
namespace Internal {
bool ClangCodeModelPlugin::initialize(const QStringList &arguments, QString *errorMessage)
{
Q_UNUSED(arguments)
Q_UNUSED(errorMessage)
addAutoReleasedObject(new ClangProjectSettingsPanelFactory);
ClangCodeModel::Internal::initializeClang();
connect(Core::EditorManager::instance(), SIGNAL(editorAboutToClose(Core::IEditor*)),
&m_liveUnitsManager, SLOT(editorAboutToClose(Core::IEditor*)));
connect(Core::EditorManager::instance(), SIGNAL(editorOpened(Core::IEditor*)),
&m_liveUnitsManager, SLOT(editorOpened(Core::IEditor*)));
PCHManager *pchManager = new PCHManager(this);
FastIndexer *fastIndexer = 0;
#ifdef CLANG_INDEXING
m_indexer.reset(new ClangIndexer);
fastIndexer = m_indexer.data();
CppTools::CppModelManagerInterface::instance()->setIndexingSupport(m_indexer->indexingSupport());
#endif // CLANG_INDEXING
// wire up the pch manager
QObject *session = ProjectExplorer::SessionManager::instance();
connect(session, SIGNAL(aboutToRemoveProject(ProjectExplorer::Project*)),
pchManager, SLOT(onAboutToRemoveProject(ProjectExplorer::Project*)));
connect(CppTools::CppModelManagerInterface::instance(), SIGNAL(projectPartsUpdated(ProjectExplorer::Project*)),
pchManager, SLOT(onProjectPartsUpdated(ProjectExplorer::Project*)));
m_modelManagerSupport.reset(new ModelManagerSupport(fastIndexer));
CppTools::CppModelManagerInterface::instance()->addModelManagerSupport(
m_modelManagerSupport.data());
return true;
}
void ClangCodeModelPlugin::extensionsInitialized()
{
}
} // namespace Internal
} // namespace Clang
Q_EXPORT_PLUGIN(ClangCodeModel::Internal::ClangCodeModelPlugin)

View File

@@ -0,0 +1,76 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef CLANGPLUGIN_H
#define CLANGPLUGIN_H
#include "clangmodelmanagersupport.h"
#include "liveunitsmanager.h"
#ifdef CLANG_INDEXING
# include "clangindexer.h"
#endif // CLANG_INDEXING
#include <extensionsystem/iplugin.h>
namespace ClangCodeModel {
namespace Internal {
class ClangCodeModelPlugin: public ExtensionSystem::IPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "ClangCodeModel.json")
public:
bool initialize(const QStringList &arguments, QString *errorMessage);
void extensionsInitialized();
private:
LiveUnitsManager m_liveUnitsManager;
QScopedPointer<ModelManagerSupport> m_modelManagerSupport;
#ifdef CLANG_INDEXING
QScopedPointer<ClangIndexer> m_indexer;
#endif // CLANG_INDEXING
#ifdef WITH_TESTS
private slots:
void test_CXX_regressions();
void test_CXX_regressions_data();
void test_CXX_snippets();
void test_CXX_snippets_data();
void test_ObjC_hints();
void test_ObjC_hints_data();
#endif
};
} // namespace Internal
} // namespace Clang
#endif // CLANGPLUGIN_H

View File

@@ -0,0 +1,208 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "clangcompleter.h"
#include "sourcemarker.h"
#include "unsavedfiledata.h"
#include "utils_p.h"
#include "completionproposalsbuilder.h"
#include "raii/scopedclangoptions.h"
#include "unit.h"
#include <QDebug>
#include <QFile>
#include <QMutex>
#include <QMutexLocker>
#include <QTime>
#include <clang-c/Index.h>
//#define TIME_COMPLETION
class ClangCodeModel::ClangCompleter::PrivateData
{
public:
PrivateData()
: m_mutex(QMutex::Recursive)
, m_isSignalSlotCompletion(false)
{
}
~PrivateData()
{
}
bool parseFromFile(const Internal::UnsavedFiles &unsavedFiles)
{
Q_ASSERT(!m_unit.isLoaded());
if (m_unit.fileName().isEmpty())
return false;
unsigned opts = clang_defaultEditingTranslationUnitOptions();
#if defined(CINDEX_VERSION) && (CINDEX_VERSION > 5)
opts |= CXTranslationUnit_CacheCompletionResults;
opts |= CXTranslationUnit_IncludeBriefCommentsInCodeCompletion;
#endif
m_unit.setManagementOptions(opts);
m_unit.setUnsavedFiles(unsavedFiles);
m_unit.parse();
return m_unit.isLoaded();
}
public:
QMutex m_mutex;
Internal::Unit m_unit;
bool m_isSignalSlotCompletion;
};
using namespace ClangCodeModel;
using namespace ClangCodeModel::Internal;
/**
* @brief Constructs with highest possible priority
*/
CodeCompletionResult::CodeCompletionResult()
: m_priority(SHRT_MAX)
, m_completionKind(Other)
, m_availability(Available)
, m_hasParameters(false)
{}
/**
* @brief Constructs with given priority
* @param priority Will be reversed, because clang's highest priority is 0,
* but inside QtCreator it is the lowest priority
*/
CodeCompletionResult::CodeCompletionResult(unsigned priority)
: m_priority(SHRT_MAX - priority)
, m_completionKind(Other)
, m_availability(Available)
, m_hasParameters(false)
{
}
ClangCompleter::ClangCompleter()
: d(new PrivateData)
{
}
ClangCompleter::~ClangCompleter()
{
}
QString ClangCompleter::fileName() const
{
return d->m_unit.fileName();
}
void ClangCompleter::setFileName(const QString &fileName)
{
if (d->m_unit.fileName() != fileName) {
d->m_unit = Internal::Unit(fileName);
}
}
QStringList ClangCompleter::options() const
{
return d->m_unit.compilationOptions();
}
void ClangCompleter::setOptions(const QStringList &options) const
{
if (d->m_unit.compilationOptions() != options) {
d->m_unit.setCompilationOptions(options);
d->m_unit.unload();
}
}
bool ClangCompleter::isSignalSlotCompletion() const
{
return d->m_isSignalSlotCompletion;
}
void ClangCompleter::setSignalSlotCompletion(bool isSignalSlot)
{
d->m_isSignalSlotCompletion = isSignalSlot;
}
bool ClangCompleter::reparse(const UnsavedFiles &unsavedFiles)
{
if (!d->m_unit.isLoaded())
return d->parseFromFile(unsavedFiles);
d->m_unit.setUnsavedFiles(unsavedFiles);
d->m_unit.reparse();
return d->m_unit.isLoaded();
}
QList<CodeCompletionResult> ClangCompleter::codeCompleteAt(unsigned line,
unsigned column,
const UnsavedFiles &unsavedFiles)
{
#ifdef TIME_COMPLETION
QTime t;t.start();
#endif // TIME_COMPLETION
if (!d->m_unit.isLoaded())
if (!d->parseFromFile(unsavedFiles))
return QList<CodeCompletionResult>();
ScopedCXCodeCompleteResults results;
d->m_unit.setUnsavedFiles(unsavedFiles);
d->m_unit.codeCompleteAt(line, column, results);
QList<CodeCompletionResult> completions;
if (results) {
const quint64 contexts = clang_codeCompleteGetContexts(results);
CompletionProposalsBuilder builder(completions, contexts, d->m_isSignalSlotCompletion);
for (unsigned i = 0; i < results.size(); ++i)
builder(results.completionAt(i));
}
#ifdef TIME_COMPLETION
qDebug() << "Completion timing:" << completions.size() << "results in" << t.elapsed() << "ms.";
#endif // TIME_COMPLETION
return completions;
}
bool ClangCompleter::objcEnabled() const
{
static const QString objcppOption = QLatin1String("-ObjC++");
static const QString objcOption = QLatin1String("-ObjC");
QStringList options = d->m_unit.compilationOptions();
return options.contains(objcOption) || options.contains(objcppOption);
}
QMutex *ClangCompleter::mutex() const
{
return &d->m_mutex;
}

View File

@@ -0,0 +1,223 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef CLANGCOMPLETER_H
#define CLANGCOMPLETER_H
#include "clang_global.h"
#include "diagnostic.h"
#include "sourcelocation.h"
#include "utils.h"
#include <QList>
#include <QMap>
#include <QMutex>
#include <QPair>
#include <QSharedPointer>
#include <QString>
#include <QStringList>
#include <QVariant>
namespace ClangCodeModel {
class SourceMarker;
class CLANG_EXPORT CodeCompletionResult
{
public:
enum Kind {
Other = 0,
FunctionCompletionKind,
ConstructorCompletionKind,
DestructorCompletionKind,
VariableCompletionKind,
ClassCompletionKind,
EnumCompletionKind,
EnumeratorCompletionKind,
NamespaceCompletionKind,
PreProcessorCompletionKind,
SignalCompletionKind,
SlotCompletionKind,
ObjCMessageCompletionKind,
KeywordCompletionKind,
ClangSnippetKind
};
enum Availability {
Available,
Deprecated,
NotAvailable,
NotAccessible
};
public:
CodeCompletionResult();
CodeCompletionResult(unsigned priority);
unsigned priority() const
{ return m_priority; }
bool isValid() const
{ return !m_text.isEmpty(); }
QString text() const
{ return m_text; }
void setText(const QString &text)
{ m_text = text; }
QString hint() const
{ return m_hint; }
void setHint(const QString &hint)
{ m_hint = hint; }
QString snippet() const
{ return m_snippet; }
void setSnippet(const QString &snippet)
{ m_snippet = snippet; }
Kind completionKind() const
{ return m_completionKind; }
void setCompletionKind(Kind type)
{ m_completionKind = type; }
int compare(const CodeCompletionResult &other) const
{
if (m_priority < other.m_priority)
return -1;
else if (m_priority > other.m_priority)
return 1;
if (m_completionKind < other.m_completionKind)
return -1;
else if (m_completionKind > other.m_completionKind)
return 1;
if (m_text < other.m_text)
return -1;
else if (m_text > other.m_text)
return 1;
if (m_hint < other.m_hint)
return -1;
else if (m_hint > other.m_hint)
return 1;
if (!m_hasParameters && other.m_hasParameters)
return -1;
else if (m_hasParameters && !other.m_hasParameters)
return 1;
if (m_availability < other.m_availability)
return -1;
else if (m_availability > other.m_availability)
return 1;
return 0;
}
bool hasParameters() const
{ return m_hasParameters; }
void setHasParameters(bool hasParameters)
{ m_hasParameters = hasParameters; }
Availability availability() const
{ return m_availability; }
void setAvailability(Availability availability)
{ m_availability = availability; }
private:
unsigned m_priority;
Kind m_completionKind;
QString m_text;
QString m_hint;
QString m_snippet;
Availability m_availability;
bool m_hasParameters;
};
inline CLANG_EXPORT uint qHash(const CodeCompletionResult &ccr)
{ return ccr.completionKind() ^ qHash(ccr.text()); }
inline CLANG_EXPORT bool operator==(const CodeCompletionResult &ccr1, const CodeCompletionResult &ccr2)
{ return ccr1.compare(ccr2) == 0; }
inline CLANG_EXPORT bool operator<(const CodeCompletionResult &ccr1, const CodeCompletionResult &ccr2)
{
return ccr1.compare(ccr2) < 0;
}
class CLANG_EXPORT ClangCompleter
{
Q_DISABLE_COPY(ClangCompleter)
class PrivateData;
public: // data structures
typedef QSharedPointer<ClangCompleter> Ptr;
public: // methods
ClangCompleter();
~ClangCompleter();
QString fileName() const;
void setFileName(const QString &fileName);
QStringList options() const;
void setOptions(const QStringList &options) const;
bool isSignalSlotCompletion() const;
void setSignalSlotCompletion(bool isSignalSlot);
bool reparse(const Internal::UnsavedFiles &unsavedFiles);
/**
* Do code-completion at the specified position.
*
* \param line The line number on which to do code-completion. The first
* line of a file has line number 1.
* \param column The column number where to do code-completion. Column
* numbers start with 1.
*/
QList<CodeCompletionResult> codeCompleteAt(unsigned line,
unsigned column,
const Internal::UnsavedFiles &unsavedFiles);
bool objcEnabled() const;
QMutex *mutex() const;
private: // instance fields
QScopedPointer<PrivateData> d;
};
} // namespace Clang
Q_DECLARE_METATYPE(ClangCodeModel::CodeCompletionResult)
#endif // CLANGCOMPLETER_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,144 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef CPPEDITOR_INTERNAL_CLANGCOMPLETION_H
#define CPPEDITOR_INTERNAL_CLANGCOMPLETION_H
#include "clangcompleter.h"
#include <cplusplus/Icons.h>
#include <cpptools/cppcompletionassistprovider.h>
#include <texteditor/codeassist/basicproposalitem.h>
#include <texteditor/codeassist/completionassistprovider.h>
#include <texteditor/codeassist/defaultassistinterface.h>
#include <texteditor/codeassist/iassistprocessor.h>
#include <QStringList>
#include <QTextCursor>
namespace ClangCodeModel {
namespace Internal {
class ClangAssistProposalModel;
class ClangCompletionAssistProvider : public CppTools::CppCompletionAssistProvider
{
public:
ClangCompletionAssistProvider();
virtual TextEditor::IAssistProcessor *createProcessor() const;
virtual TextEditor::IAssistInterface *createAssistInterface(
ProjectExplorer::Project *project, TextEditor::BaseTextEditor *editor,
QTextDocument *document, int position, TextEditor::AssistReason reason) const;
private:
ClangCodeModel::ClangCompleter::Ptr m_clangCompletionWrapper;
};
} // namespace Internal
class CLANG_EXPORT ClangCompletionAssistInterface: public TextEditor::DefaultAssistInterface
{
public:
ClangCompletionAssistInterface(ClangCodeModel::ClangCompleter::Ptr clangWrapper,
QTextDocument *document,
int position,
const QString &fileName,
TextEditor::AssistReason reason,
const QStringList &options,
const QStringList &includePaths,
const QStringList &frameworkPaths,
const Internal::PchInfo::Ptr &pchInfo);
ClangCodeModel::ClangCompleter::Ptr clangWrapper() const
{ return m_clangWrapper; }
const ClangCodeModel::Internal::UnsavedFiles &unsavedFiles() const
{ return m_unsavedFiles; }
bool objcEnabled() const;
const QStringList &options() const
{ return m_options; }
const QStringList &includePaths() const
{ return m_includePaths; }
const QStringList &frameworkPaths() const
{ return m_frameworkPaths; }
private:
ClangCodeModel::ClangCompleter::Ptr m_clangWrapper;
ClangCodeModel::Internal::UnsavedFiles m_unsavedFiles;
QStringList m_options, m_includePaths, m_frameworkPaths;
Internal::PchInfo::Ptr m_savedPchPointer;
};
class CLANG_EXPORT ClangCompletionAssistProcessor : public TextEditor::IAssistProcessor
{
public:
ClangCompletionAssistProcessor();
virtual ~ClangCompletionAssistProcessor();
virtual TextEditor::IAssistProposal *perform(const TextEditor::IAssistInterface *interface);
private:
int startCompletionHelper();
int startOfOperator(int pos, unsigned *kind, bool wantFunctionCall) const;
int findStartOfName(int pos = -1) const;
bool accepts() const;
TextEditor::IAssistProposal *createContentProposal();
int startCompletionInternal(const QString fileName,
unsigned line, unsigned column,
int endOfExpression);
bool completeInclude(const QTextCursor &cursor);
void completeIncludePath(const QString &realPath, const QStringList &suffixes);
void completePreprocessor();
void addCompletionItem(const QString &text,
const QIcon &icon = QIcon(),
int order = 0,
const QVariant &data = QVariant());
private:
int m_startPosition;
QScopedPointer<const ClangCompletionAssistInterface> m_interface;
QList<TextEditor::BasicProposalItem *> m_completions;
CPlusPlus::Icons m_icons;
QStringList m_preprocessorCompletions;
QScopedPointer<Internal::ClangAssistProposalModel> m_model;
TextEditor::IAssistProposal *m_hintProposal;
};
} // namespace Clang
#endif // CPPEDITOR_INTERNAL_CLANGCOMPLETION_H

View File

@@ -0,0 +1,99 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "clanghighlightingsupport.h"
#include <coreplugin/idocument.h>
#include <texteditor/basetexteditor.h>
#include <texteditor/itexteditor.h>
#include <QTextBlock>
#include <QTextEdit>
#include "pchmanager.h"
using namespace ClangCodeModel;
using namespace ClangCodeModel::Internal;
using namespace CppTools;
ClangHighlightingSupport::ClangHighlightingSupport(TextEditor::ITextEditor *textEditor, FastIndexer *fastIndexer)
: CppHighlightingSupport(textEditor)
, m_fastIndexer(fastIndexer)
, m_semanticMarker(new ClangCodeModel::SemanticMarker)
{
}
ClangHighlightingSupport::~ClangHighlightingSupport()
{
}
bool ClangHighlightingSupport::hightlighterHandlesIfdefedOutBlocks() const
{
#if CINDEX_VERSION_MINOR >= 21
return true;
#else
return false;
#endif
}
QFuture<TextEditor::HighlightingResult> ClangHighlightingSupport::highlightingFuture(
const CPlusPlus::Document::Ptr &doc,
const CPlusPlus::Snapshot &snapshot) const
{
Q_UNUSED(doc);
Q_UNUSED(snapshot);
TextEditor::BaseTextEditorWidget *ed = qobject_cast<TextEditor::BaseTextEditorWidget *>(editor()->widget());
int firstLine = 1;
int lastLine = ed->document()->blockCount();
const QString fileName = editor()->document()->filePath();
CppModelManagerInterface *modelManager = CppModelManagerInterface::instance();
QList<ProjectPart::Ptr> parts = modelManager->projectPart(fileName);
if (parts.isEmpty())
parts += modelManager->fallbackProjectPart();
QStringList options;
PchInfo::Ptr pchInfo;
foreach (const ProjectPart::Ptr &part, parts) {
if (part.isNull())
continue;
options = Utils::createClangOptions(part, fileName);
pchInfo = PCHManager::instance()->pchInfo(part);
if (!pchInfo.isNull())
options.append(ClangCodeModel::Utils::createPCHInclusionOptions(pchInfo->fileName()));
if (!options.isEmpty())
break;
}
CreateMarkers *createMarkers = CreateMarkers::create(m_semanticMarker,
fileName, options,
firstLine, lastLine,
m_fastIndexer, pchInfo);
return createMarkers->start();
}

View File

@@ -0,0 +1,69 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef CLANG_CLANGHIGHLIGHTINGSUPPORT_H
#define CLANG_CLANGHIGHLIGHTINGSUPPORT_H
#include "clangutils.h"
#include "cppcreatemarkers.h"
#include "fastindexer.h"
#include <cpptools/cpphighlightingsupport.h>
#include <QObject>
#include <QScopedPointer>
namespace ClangCodeModel {
class ClangHighlightingSupport: public CppTools::CppHighlightingSupport
{
public:
ClangHighlightingSupport(TextEditor::ITextEditor *textEditor,
Internal::FastIndexer *fastIndexer);
~ClangHighlightingSupport();
virtual bool requiresSemanticInfo() const
{ return false; }
virtual bool hightlighterHandlesDiagnostics() const
{ return true; }
virtual bool hightlighterHandlesIfdefedOutBlocks() const;
virtual QFuture<TextEditor::HighlightingResult> highlightingFuture(
const CPlusPlus::Document::Ptr &doc, const CPlusPlus::Snapshot &snapshot) const;
private:
Internal::FastIndexer *m_fastIndexer;
ClangCodeModel::SemanticMarker::Ptr m_semanticMarker;
};
} // namespace ClangCodeModel
#endif // CLANG_CLANGHIGHLIGHTINGSUPPORT_H

View File

@@ -0,0 +1,169 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "clangindexer.h"
#include "clangsymbolsearcher.h"
#include "clangutils.h"
#include "indexer.h"
#include "liveunitsmanager.h"
#include <coreplugin/icore.h>
#include <coreplugin/progressmanager/progressmanager.h>
#include <cpptools/cppmodelmanagerinterface.h>
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/session.h>
#include <QDir>
using namespace ClangCodeModel;
using namespace ClangCodeModel::Internal;
ClangIndexingSupport::ClangIndexingSupport(ClangIndexer *indexer)
: m_indexer(indexer)
{
}
ClangIndexingSupport::~ClangIndexingSupport()
{
}
QFuture<void> ClangIndexingSupport::refreshSourceFiles(const QStringList &sourceFiles)
{
return m_indexer->refreshSourceFiles(sourceFiles);
}
CppTools::SymbolSearcher *ClangIndexingSupport::createSymbolSearcher(CppTools::SymbolSearcher::Parameters parameters, QSet<QString> fileNames)
{
return new ClangSymbolSearcher(m_indexer, parameters, fileNames);
}
ClangIndexer::ClangIndexer()
: QObject(0)
, m_indexingSupport(new ClangIndexingSupport(this))
, m_isLoadingSession(false)
, m_clangIndexer(new Indexer(this))
{
connect(m_clangIndexer, SIGNAL(indexingStarted(QFuture<void>)),
this, SLOT(onIndexingStarted(QFuture<void>)));
ProjectExplorer::ProjectExplorerPlugin *pe =
ProjectExplorer::ProjectExplorerPlugin::instance();
ProjectExplorer::SessionManager *session = pe->session();
connect(session, SIGNAL(aboutToLoadSession(QString)),
this, SLOT(onAboutToLoadSession(QString)));
connect(session, SIGNAL(sessionLoaded(QString)),
this, SLOT(onSessionLoaded(QString)));
connect(session, SIGNAL(aboutToSaveSession()),
this, SLOT(onAboutToSaveSession()));
}
ClangIndexer::~ClangIndexer()
{
m_clangIndexer->cancel(true);
}
CppTools::CppIndexingSupport *ClangIndexer::indexingSupport()
{
return m_indexingSupport.data();
}
QFuture<void> ClangIndexer::refreshSourceFiles(const QStringList &sourceFiles)
{
typedef CppTools::ProjectPart ProjectPart;
CppTools::CppModelManagerInterface *mmi = CppTools::CppModelManagerInterface::instance();
LiveUnitsManager *lum = LiveUnitsManager::instance();
if (m_clangIndexer->isBusy())
m_clangIndexer->cancel(true);
foreach (const QString &file, sourceFiles) {
if (lum->isTracking(file))
continue; // we get notified separately about open files.
const QList<ProjectPart::Ptr> &parts = mmi->projectPart(file);
if (!parts.isEmpty())
m_clangIndexer->addFile(file, parts.at(0));
else
m_clangIndexer->addFile(file, ProjectPart::Ptr());
}
if (!m_isLoadingSession)
m_clangIndexer->regenerate();
return QFuture<void>();
}
void ClangIndexer::match(ClangSymbolSearcher *searcher) const
{
m_clangIndexer->match(searcher);
}
void ClangIndexer::onAboutToLoadSession(const QString &sessionName)
{
m_isLoadingSession = true;
if (sessionName == QLatin1String("default"))
return;
QString path = Core::ICore::instance()->userResourcePath() + QLatin1String("/codemodel/");
if (QFile::exists(path) || QDir().mkpath(path))
m_clangIndexer->initialize(path + sessionName + QLatin1String(".qci"));
}
void ClangIndexer::onSessionLoaded(QString)
{
m_isLoadingSession = false;
m_clangIndexer->regenerate();
}
void ClangIndexer::onAboutToSaveSession()
{
m_clangIndexer->finalize();
}
void ClangIndexer::indexNow(const ClangCodeModel::Internal::Unit &unit)
{
typedef CppTools::ProjectPart ProjectPart;
QString file = unit.fileName();
CppTools::CppModelManagerInterface *mmi = CppTools::CppModelManagerInterface::instance();
const QList<ProjectPart::Ptr> &parts = mmi->projectPart(file);
ProjectPart::Ptr part;
if (!parts.isEmpty())
part = parts.at(0);
if (!m_isLoadingSession)
m_clangIndexer->runQuickIndexing(unit, part);
}
void ClangIndexer::onIndexingStarted(QFuture<void> indexingFuture)
{
Core::ICore::instance()->progressManager()->addTask(indexingFuture,
tr("C++ Indexing"),
QLatin1String("Key.Temp.Indexing"));
}

View File

@@ -0,0 +1,94 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef CLANGINDEXER_H
#define CLANGINDEXER_H
#include "fastindexer.h"
#include <cpptools/cppindexingsupport.h>
#include <QObject>
namespace ClangCodeModel {
class Indexer;
namespace Internal {
class ClangIndexer;
class ClangSymbolSearcher;
class ClangIndexingSupport: public CppTools::CppIndexingSupport
{
public:
ClangIndexingSupport(ClangIndexer *indexer);
virtual ~ClangIndexingSupport();
virtual QFuture<void> refreshSourceFiles(const QStringList &sourceFiles);
virtual CppTools::SymbolSearcher *createSymbolSearcher(CppTools::SymbolSearcher::Parameters parameters, QSet<QString> fileNames);
private:
ClangIndexer *m_indexer;
};
class ClangIndexer: public QObject, public FastIndexer
{
Q_OBJECT
public:
ClangIndexer();
~ClangIndexer();
CppTools::CppIndexingSupport *indexingSupport();
QFuture<void> refreshSourceFiles(const QStringList &sourceFiles);
void match(ClangSymbolSearcher *searcher) const;
void indexNow(const Unit &unit);
public slots:
void onAboutToLoadSession(const QString &sessionName);
void onSessionLoaded(QString);
void onAboutToSaveSession();
private slots:
void onIndexingStarted(QFuture<void> indexingFuture);
private:
QScopedPointer<ClangIndexingSupport> m_indexingSupport;
bool m_isLoadingSession;
Indexer *m_clangIndexer;
};
} // namespace Internal
} // namespace ClangCodeModel
#endif // CLANGINDEXER_H

View File

@@ -0,0 +1,69 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "clangcompletion.h"
#include "clanghighlightingsupport.h"
#include "clangmodelmanagersupport.h"
#include <QCoreApplication>
using namespace ClangCodeModel;
using namespace ClangCodeModel::Internal;
ModelManagerSupport::ModelManagerSupport(FastIndexer *fastIndexer)
: m_completionAssistProvider(new ClangCompletionAssistProvider)
, m_fastIndexer(fastIndexer)
{
}
ModelManagerSupport::~ModelManagerSupport()
{
}
QString ModelManagerSupport::id() const
{
return QLatin1String("ClangCodeMode.ClangCodeMode");
}
QString ModelManagerSupport::displayName() const
{
return QCoreApplication::translate("ModelManagerSupport::displayName",
"Clang");
}
CppTools::CppCompletionAssistProvider *ModelManagerSupport::completionAssistProvider()
{
return m_completionAssistProvider.data();
}
CppTools::CppHighlightingSupport *ModelManagerSupport::highlightingSupport(
TextEditor::ITextEditor *editor)
{
return new ClangHighlightingSupport(editor, m_fastIndexer);
}

View File

@@ -0,0 +1,64 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef CLANGCODEMODEL_INTERNAL_CLANGMODELMANAGERSUPPORT_H
#define CLANGCODEMODEL_INTERNAL_CLANGMODELMANAGERSUPPORT_H
#include <cpptools/cppmodelmanagersupport.h>
#include <QScopedPointer>
namespace ClangCodeModel {
namespace Internal {
class FastIndexer;
class ModelManagerSupport: public CppTools::ModelManagerSupport
{
Q_DISABLE_COPY(ModelManagerSupport)
public:
ModelManagerSupport(FastIndexer *fastIndexer);
virtual ~ModelManagerSupport();
virtual QString id() const;
virtual QString displayName() const;
virtual CppTools::CppCompletionAssistProvider *completionAssistProvider();
virtual CppTools::CppHighlightingSupport *highlightingSupport(TextEditor::ITextEditor *editor);
private:
QScopedPointer<CppTools::CppCompletionAssistProvider> m_completionAssistProvider;
FastIndexer *m_fastIndexer;
};
} // namespace Internal
} // namespace ClangCodeModel
#endif // CLANGCODEMODEL_INTERNAL_CLANGMODELMANAGERSUPPORT_H

View File

@@ -0,0 +1,108 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "clangprojectsettings.h"
using namespace ClangCodeModel;
ClangProjectSettings::ClangProjectSettings(ProjectExplorer::Project *project)
: m_project(project)
, m_pchUsage(PchUse_None)
{
Q_ASSERT(project);
connect(project, SIGNAL(settingsLoaded()),
this, SLOT(pullSettings()));
connect(project, SIGNAL(aboutToSaveSettings()),
this, SLOT(pushSettings()));
}
ClangProjectSettings::~ClangProjectSettings()
{
}
ProjectExplorer::Project *ClangProjectSettings::project() const
{
return m_project;
}
ClangProjectSettings::PchUsage ClangProjectSettings::pchUsage() const
{
return m_pchUsage;
}
void ClangProjectSettings::setPchUsage(ClangProjectSettings::PchUsage pchUsage)
{
if (pchUsage < PchUse_None || pchUsage > PchUse_Custom)
return;
if (m_pchUsage != pchUsage) {
m_pchUsage = pchUsage;
emit pchSettingsChanged();
}
}
QString ClangProjectSettings::customPchFile() const
{
return m_customPchFile;
}
void ClangProjectSettings::setCustomPchFile(const QString &customPchFile)
{
if (m_customPchFile != customPchFile) {
m_customPchFile = customPchFile;
emit pchSettingsChanged();
}
}
static QLatin1String PchUsageKey("PchUsage");
static QLatin1String CustomPchFileKey("CustomPchFile");
static QLatin1String SettingsNameKey("ClangProjectSettings");
void ClangProjectSettings::pushSettings()
{
QVariantMap settings;
settings[PchUsageKey] = m_pchUsage;
settings[CustomPchFileKey] = m_customPchFile;
QVariant s(settings);
m_project->setNamedSettings(SettingsNameKey, s);
}
void ClangProjectSettings::pullSettings()
{
QVariant s = m_project->namedSettings(SettingsNameKey);
QVariantMap settings = s.toMap();
const PchUsage storedPchUsage = static_cast<PchUsage>(
settings.value(PchUsageKey, PchUse_Unknown).toInt());
if (storedPchUsage != PchUse_Unknown)
setPchUsage(storedPchUsage);
setCustomPchFile(settings.value(CustomPchFileKey).toString());
}

View File

@@ -0,0 +1,82 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef CLANGPROJECTSETTINGS_H
#define CLANGPROJECTSETTINGS_H
#include "clang_global.h"
#include <projectexplorer/project.h>
#include <QObject>
#include <QString>
namespace ClangCodeModel {
class CLANG_EXPORT ClangProjectSettings: public QObject
{
Q_OBJECT
public:
enum PchUsage {
PchUse_Unknown = 0,
PchUse_None = 1,
PchUse_BuildSystem_Exact = 2,
PchUse_BuildSystem_Fuzzy = 3,
PchUse_Custom = 4
};
public:
ClangProjectSettings(ProjectExplorer::Project *project);
virtual ~ClangProjectSettings();
ProjectExplorer::Project *project() const;
PchUsage pchUsage() const;
void setPchUsage(PchUsage pchUsage);
QString customPchFile() const;
void setCustomPchFile(const QString &customPchFile);
signals:
void pchSettingsChanged();
public slots:
void pullSettings();
void pushSettings();
private:
ProjectExplorer::Project *m_project;
PchUsage m_pchUsage;
QString m_customPchFile;
};
} // ClangCodeModel namespace
#endif // CLANGPROJECTSETTINGS_H

View File

@@ -0,0 +1,165 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "clangprojectsettings.h"
#include "clangprojectsettingspropertiespage.h"
#include "pchmanager.h"
#include <QButtonGroup>
#include <QCoreApplication>
#include <QFileDialog>
using namespace ProjectExplorer;
using namespace ClangCodeModel::Internal;
static const char CLANGPROJECTSETTINGS_PANEL_ID[] = "ClangCodeModel.ProjectPanel";
QString ClangProjectSettingsPanelFactory::id() const
{
return QLatin1String(CLANGPROJECTSETTINGS_PANEL_ID);
}
QString ClangProjectSettingsPanelFactory::displayName() const
{
return QCoreApplication::translate("ClangProjectSettingsPropertiesPage",
"Clang Settings");
}
int ClangProjectSettingsPanelFactory::priority() const
{
return 60;
}
bool ClangProjectSettingsPanelFactory::supports(Project *project)
{
Q_UNUSED(project);
return true;
}
PropertiesPanel *ClangProjectSettingsPanelFactory::createPanel(Project *project)
{
PropertiesPanel *panel = new PropertiesPanel;
panel->setDisplayName(QCoreApplication::translate(
"ClangProjectSettingsPropertiesPage",
"Clang Settings"));
panel->setWidget(new ClangProjectSettingsWidget(project));
return panel;
}
ClangProjectSettingsWidget::ClangProjectSettingsWidget(Project *project)
: m_project(project)
{
m_ui.setupUi(this);
ClangProjectSettings *cps = PCHManager::instance()->settingsForProject(project);
Q_ASSERT(cps);
QButtonGroup *pchGroup = new QButtonGroup(this);
pchGroup->addButton(m_ui.noneButton, ClangProjectSettings::PchUse_None);
pchGroup->addButton(m_ui.exactButton, ClangProjectSettings::PchUse_BuildSystem_Exact);
pchGroup->addButton(m_ui.fuzzyButton, ClangProjectSettings::PchUse_BuildSystem_Fuzzy);
pchGroup->addButton(m_ui.customButton, ClangProjectSettings::PchUse_Custom);
switch (cps->pchUsage()) {
case ClangProjectSettings::PchUse_None:
case ClangProjectSettings::PchUse_BuildSystem_Exact:
case ClangProjectSettings::PchUse_BuildSystem_Fuzzy:
case ClangProjectSettings::PchUse_Custom:
pchGroup->button(cps->pchUsage())->setChecked(true);
break;
default: break;
}
pchUsageChanged(cps->pchUsage());
connect(pchGroup, SIGNAL(buttonClicked(int)),
this, SLOT(pchUsageChanged(int)));
m_ui.customField->setText(cps->customPchFile());
connect(m_ui.customField, SIGNAL(editingFinished()),
this, SLOT(customPchFileChanged()));
connect(m_ui.customButton, SIGNAL(clicked()),
this, SLOT(customPchButtonClicked()));
}
void ClangProjectSettingsWidget::pchUsageChanged(int id)
{
ClangProjectSettings *cps = PCHManager::instance()->settingsForProject(m_project);
Q_ASSERT(cps);
cps->setPchUsage(static_cast<ClangProjectSettings::PchUsage>(id));
switch (id) {
case ClangProjectSettings::PchUse_None:
case ClangProjectSettings::PchUse_BuildSystem_Fuzzy:
case ClangProjectSettings::PchUse_BuildSystem_Exact:
m_ui.customField->setEnabled(false);
m_ui.chooseButton->setEnabled(false);
break;
case ClangProjectSettings::PchUse_Custom:
m_ui.customField->setEnabled(true);
m_ui.chooseButton->setEnabled(true);
break;
default:
break;
}
}
void ClangProjectSettingsWidget::customPchFileChanged()
{
ClangProjectSettings *cps = PCHManager::instance()->settingsForProject(m_project);
Q_ASSERT(cps);
if (cps->pchUsage() != ClangProjectSettings::PchUse_Custom)
return;
QString fileName = m_ui.customField->text();
if (!QFile(fileName).exists())
return;
cps->setCustomPchFile(fileName);
}
void ClangProjectSettingsWidget::customPchButtonClicked()
{
ClangProjectSettings *cps = PCHManager::instance()->settingsForProject(m_project);
Q_ASSERT(cps);
QFileDialog d(this);
d.setNameFilters(QStringList() << tr("Header Files (*.h)")
<< tr("All Files (*)"));
d.setFileMode(QFileDialog::ExistingFile);
d.setDirectory(m_project->projectDirectory());
if (!d.exec())
return;
const QStringList fileNames = d.selectedFiles();
if (fileNames.isEmpty() || fileNames.first().isEmpty())
return;
m_ui.customField->setText(fileNames.first());
cps->setCustomPchFile(fileNames.first());
}

View File

@@ -0,0 +1,72 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef CLANGPROJECTSETTINGSPROPERTIESPAGE_H
#define CLANGPROJECTSETTINGSPROPERTIESPAGE_H
#include "ui_clangprojectsettingspropertiespage.h"
#include <projectexplorer/iprojectproperties.h>
#include <QString>
namespace ClangCodeModel {
namespace Internal {
class ClangProjectSettingsPanelFactory: public ProjectExplorer::IProjectPanelFactory
{
public:
QString id() const;
QString displayName() const;
int priority() const;
bool supports(ProjectExplorer::Project *project);
ProjectExplorer::PropertiesPanel *createPanel(ProjectExplorer::Project *project);
};
class ClangProjectSettingsWidget: public QWidget
{
Q_OBJECT
public:
ClangProjectSettingsWidget(ProjectExplorer::Project *project);
protected slots:
void pchUsageChanged(int id);
void customPchFileChanged();
void customPchButtonClicked();
private:
Ui::ClangProjectSettingsPropertiesPage m_ui;
ProjectExplorer::Project *m_project;
};
} // ClangCodeModel namespace
} // Internal namespace
#endif // CLANGPROJECTSETTINGSPROPERTIESPAGE_H

View File

@@ -0,0 +1,87 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ClangCodeModel::Internal::ClangProjectSettingsPropertiesPage</class>
<widget class="QWidget" name="ClangCodeModel::Internal::ClangProjectSettingsPropertiesPage">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>814</width>
<height>330</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Pre-compiled headers:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QRadioButton" name="noneButton">
<property name="text">
<string>None</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QRadioButton" name="exactButton">
<property name="text">
<string>Build system (exact)</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QRadioButton" name="fuzzyButton">
<property name="text">
<string>Build system (fuzzy)</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QRadioButton" name="customButton">
<property name="text">
<string>Custom</string>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QLineEdit" name="customField">
<property name="enabled">
<bool>false</bool>
</property>
</widget>
</item>
<item row="3" column="3">
<widget class="QPushButton" name="chooseButton">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Choose...</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>12</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -0,0 +1,155 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "clangsymbolsearcher.h"
#include "symbol.h"
#include <cpptools/searchsymbols.h>
#include <cassert>
using namespace ClangCodeModel;
using namespace ClangCodeModel::Internal;
ClangSymbolSearcher::ClangSymbolSearcher(ClangIndexer *indexer, const Parameters &parameters, QSet<QString> fileNames, QObject *parent)
: CppTools::SymbolSearcher(parent)
, m_indexer(indexer)
, m_parameters(parameters)
, m_fileNames(fileNames)
, m_future(0)
{
assert(indexer);
}
ClangSymbolSearcher::~ClangSymbolSearcher()
{
}
void ClangSymbolSearcher::runSearch(QFutureInterface<SearchResultItem> &future)
{
m_future = &future;
m_indexer->match(this);
m_future = 0;
}
void ClangSymbolSearcher::search(const QLinkedList<Symbol> &allSymbols)
{
QString findString = (m_parameters.flags & Find::FindRegularExpression
? m_parameters.text : QRegExp::escape(m_parameters.text));
if (m_parameters.flags & Find::FindWholeWords)
findString = QString::fromLatin1("\\b%1\\b").arg(findString);
QRegExp matcher(findString, (m_parameters.flags & Find::FindCaseSensitively
? Qt::CaseSensitive : Qt::CaseInsensitive));
const int chunkSize = 10;
QVector<Find::SearchResultItem> resultItems;
resultItems.reserve(100);
m_future->setProgressRange(0, allSymbols.size() % chunkSize);
m_future->setProgressValue(0);
int symbolNr = 0;
foreach (const Symbol &s, allSymbols) {
if (symbolNr % chunkSize == 0) {
m_future->setProgressValue(symbolNr / chunkSize);
m_future->reportResults(resultItems);
resultItems.clear();
if (m_future->isPaused())
m_future->waitForResume();
if (m_future->isCanceled())
return;
}
++symbolNr;
CppTools::ModelItemInfo info;
switch (s.m_kind) {
case Symbol::Enum:
if (m_parameters.types & SymbolSearcher::Enums) {
info.type = CppTools::ModelItemInfo::Enum;
info.symbolType = QLatin1String("enum");
break;
} else {
continue;
}
case Symbol::Class:
if (m_parameters.types & SymbolSearcher::Classes) {
info.type = CppTools::ModelItemInfo::Class;
info.symbolType = QLatin1String("class");
break;
} else {
continue;
}
case Symbol::Method:
case Symbol::Function:
case Symbol::Constructor:
case Symbol::Destructor:
if (m_parameters.types & SymbolSearcher::Functions) {
info.type = CppTools::ModelItemInfo::Method;
break;
} else {
continue;
}
case Symbol::Declaration:
if (m_parameters.types & SymbolSearcher::Declarations) {
info.type = CppTools::ModelItemInfo::Declaration;
break;
} else {
continue;
}
default: continue;
}
if (matcher.indexIn(s.m_name) == -1)
continue;
info.symbolName = s.m_name;
info.fullyQualifiedName = s.m_qualification.split(QLatin1String("::")) << s.m_name;
info.fileName = s.m_location.fileName();
info.icon = s.iconForSymbol();
info.line = s.m_location.line();
info.column = s.m_location.column() - 1;
Find::SearchResultItem item;
item.path << s.m_qualification;
item.text = s.m_name;
item.icon = info.icon;
item.textMarkPos = -1;
item.textMarkLength = 0;
item.lineNumber = -1;
item.userData = qVariantFromValue(info);
resultItems << item;
}
if (!resultItems.isEmpty())
m_future->reportResults(resultItems);
}

View File

@@ -0,0 +1,69 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef CLANGSYMBOLSEARCHER_H
#define CLANGSYMBOLSEARCHER_H
#include "clangindexer.h"
#include <cpptools/cppindexingsupport.h>
#include <QLinkedList>
namespace ClangCodeModel {
class Symbol;
namespace Internal {
class ClangSymbolSearcher: public CppTools::SymbolSearcher
{
Q_OBJECT
typedef CppTools::SymbolSearcher::Parameters Parameters;
typedef Find::SearchResultItem SearchResultItem;
public:
ClangSymbolSearcher(ClangIndexer *indexer, const Parameters &parameters, QSet<QString> fileNames, QObject *parent = 0);
virtual ~ClangSymbolSearcher();
virtual void runSearch(QFutureInterface<SearchResultItem> &future);
void search(const QLinkedList<Symbol> &allSymbols);
private:
ClangIndexer *m_indexer;
const Parameters m_parameters;
const QSet<QString> m_fileNames;
QFutureInterface<SearchResultItem> *m_future;
};
} // namespace Internal
} // namespace ClangCodeModel
#endif // CLANGSYMBOLSEARCHER_H

View File

@@ -0,0 +1,322 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "clangutils.h"
#include <clang-c/Index.h>
#include <coreplugin/documentmanager.h>
#include <coreplugin/icore.h>
#include <coreplugin/idocument.h>
#include <QFile>
#include <QSet>
#include <QString>
using namespace ClangCodeModel;
using namespace ClangCodeModel::Internal;
using namespace Core;
using namespace CppTools;
namespace ClangCodeModel {
namespace Utils {
namespace {
bool isBlacklisted(const QString &path)
{
static QStringList blacklistedPaths = QStringList()
<< QLatin1String("lib/gcc/i686-apple-darwin");
foreach (const QString &blacklisted, blacklistedPaths)
if (path.contains(blacklisted))
return true;
return false;
}
} // anonymous namespace
UnsavedFiles createUnsavedFiles(CppModelManagerInterface::WorkingCopy workingCopy)
{
// TODO: change the modelmanager to hold one working copy, and amend it every time we ask for one.
// TODO: Reason: the UnsavedFile needs a QByteArray.
QSet<QString> modifiedFiles;
foreach (IDocument *doc, Core::DocumentManager::modifiedDocuments())
modifiedFiles.insert(doc->filePath());
UnsavedFiles result;
QHashIterator<QString, QPair<QByteArray, unsigned> > wcIter = workingCopy.iterator();
while (wcIter.hasNext()) {
wcIter.next();
const QString &fileName = wcIter.key();
if (modifiedFiles.contains(fileName) && QFile(fileName).exists())
result.insert(fileName, wcIter.value().first);
}
return result;
}
/**
* @brief Creates list of command-line arguments required for correct parsing
* @param pPart Null if file isn't part of any project
* @param fileName Path to file, non-empty
*/
QStringList createClangOptions(const ProjectPart::Ptr &pPart, const QString &fileName)
{
ProjectFile::Kind fileKind = ProjectFile::Unclassified;
if (!pPart.isNull())
foreach (const ProjectFile &file, pPart->files)
if (file.path == fileName) {
fileKind = file.kind;
break;
}
if (fileKind == ProjectFile::Unclassified)
fileKind = ProjectFile::classify(fileName);
return createClangOptions(pPart, fileKind);
}
static QStringList buildDefines(const QByteArray &defines, bool toolchainDefines)
{
QStringList result;
foreach (QByteArray def, defines.split('\n')) {
if (def.isEmpty())
continue;
if (toolchainDefines) {
//### FIXME: the next 3 check shouldn't be needed: we probably don't want to get the compiler-defined defines in.
if (!def.startsWith("#define "))
continue;
if (def.startsWith("#define _"))
continue;
if (def.startsWith("#define OBJC_NEW_PROPERTIES"))
continue;
}
QByteArray str = def.mid(8);
int spaceIdx = str.indexOf(' ');
QString arg;
if (spaceIdx != -1) {
arg = QLatin1String("-D" + str.left(spaceIdx) + "=" + str.mid(spaceIdx + 1));
} else {
arg = QLatin1String("-D" + str);
}
arg = arg.replace(QLatin1String("\\\""), QLatin1String("\""));
arg = arg.replace(QLatin1String("\""), QLatin1String(""));
if (!result.contains(arg))
result.append(arg);
}
return result;
}
/**
* @brief Creates list of command-line arguments required for correct parsing
* @param pPart Null if file isn't part of any project
* @param fileKind Determines language and source/header state
*/
QStringList createClangOptions(const ProjectPart::Ptr &pPart, ProjectFile::Kind fileKind)
{
QStringList result = clangLanguageOption(fileKind);
switch (fileKind) {
default:
case CppTools::ProjectFile::CXXHeader:
case CppTools::ProjectFile::CXXSource:
case CppTools::ProjectFile::ObjCXXHeader:
case CppTools::ProjectFile::ObjCXXSource:
case CppTools::ProjectFile::CudaSource:
case CppTools::ProjectFile::OpenCLSource:
result << clangOptionsForCxx(pPart->qtVersion,
pPart->cxxVersion,
pPart->cxxExtensions);
break;
case CppTools::ProjectFile::CHeader:
case CppTools::ProjectFile::CSource:
case CppTools::ProjectFile::ObjCHeader:
case CppTools::ProjectFile::ObjCSource:
result << clangOptionsForC(pPart->cVersion,
pPart->cxxExtensions);
break;
}
if (pPart.isNull())
return result;
result << QLatin1String("-nostdinc");
result << buildDefines(pPart->toolchainDefines, true);
result << buildDefines(pPart->projectDefines, false);
foreach (const QString &frameworkPath, pPart->frameworkPaths)
result.append(QLatin1String("-F") + frameworkPath);
foreach (const QString &inc, pPart->includePaths)
if (!inc.isEmpty() && !isBlacklisted(inc))
result << (QLatin1String("-I") + inc);
#if 0
qDebug() << "--- m_args:";
foreach (const QString &arg, result)
qDebug() << "\t" << qPrintable(arg);
qDebug() << "---";
#endif
return result;
}
/// @return Option to speed up parsing with precompiled header
QStringList createPCHInclusionOptions(const QStringList &pchFiles)
{
QStringList opts;
foreach (const QString &pchFile, pchFiles) {
if (QFile(pchFile).exists()) {
opts += QLatin1String("-include-pch");
opts += pchFile;
}
}
return opts;
}
/// @return Option to speed up parsing with precompiled header
QStringList createPCHInclusionOptions(const QString &pchFile)
{
return createPCHInclusionOptions(QStringList() << pchFile);
}
/// @return "-std" flag to select standard, flags for C extensions
QStringList clangOptionsForC(ProjectPart::CVersion cVersion, ProjectPart::CXXExtensions cxxExtensions)
{
QStringList opts;
bool gnuExpensions = cxxExtensions & ProjectPart::GnuExtensions;
switch (cVersion) {
case ProjectPart::C89:
opts << (gnuExpensions ? QLatin1String("-std=gnu89") : QLatin1String("-std=c89"));
break;
case ProjectPart::C99:
opts << (gnuExpensions ? QLatin1String("-std=gnu99") : QLatin1String("-std=c99"));
break;
case ProjectPart::C11:
opts << (gnuExpensions ? QLatin1String("-std=gnu11") : QLatin1String("-std=c11"));
break;
}
if (cxxExtensions & ProjectPart::MicrosoftExtensions) {
opts << QLatin1String("-fms-extensions");
}
#if defined(CINDEX_VERSION) // clang 3.2 or higher
if (cxxExtensions & ProjectPart::BorlandExtensions)
opts << QLatin1String("-fborland-extensions");
#endif
return opts;
}
/// @return "-std" flag to select standard, flags for C++ extensions, Qt injections
QStringList clangOptionsForCxx(ProjectPart::QtVersion qtVersion,
ProjectPart::CXXVersion cxxVersion,
ProjectPart::CXXExtensions cxxExtensions)
{
QStringList opts;
bool gnuExpensions = cxxExtensions & ProjectPart::GnuExtensions;
switch (cxxVersion) {
case ProjectPart::CXX11:
opts << (gnuExpensions ? QLatin1String("-std=gnu++11") : QLatin1String("-std=c++11"));
break;
case ProjectPart::CXX98:
opts << (gnuExpensions ? QLatin1String("-std=gnu++98") : QLatin1String("-std=c++98"));
break;
}
if (cxxExtensions & ProjectPart::MicrosoftExtensions) {
opts << QLatin1String("-fms-extensions")
<< QLatin1String("-fdelayed-template-parsing");
}
#if defined(CINDEX_VERSION) // clang 3.2 or higher
if (cxxExtensions & ProjectPart::BorlandExtensions)
opts << QLatin1String("-fborland-extensions");
#endif
static const QString injectedHeader(Core::ICore::instance()->resourcePath() + QLatin1String("/cplusplus/qt%1-qobjectdefs-injected.h"));
// if (qtVersion == ProjectPart::Qt4)
// opts << QLatin1String("-include") << injectedHeader.arg(QLatin1Char('4'));
if (qtVersion == ProjectPart::Qt5)
opts << QLatin1String("-include") << injectedHeader.arg(QLatin1Char('5'));
return opts;
}
/// @return "-x language-code"
QStringList clangLanguageOption(ProjectFile::Kind fileKind)
{
QStringList opts;
opts += QLatin1String("-x");
switch (fileKind) {
case ProjectFile::CHeader:
// opts += QLatin1String("c-header");
// break;
case ProjectFile::CXXHeader:
default:
opts += QLatin1String("c++-header");
break;
case ProjectFile::CXXSource:
opts += QLatin1String("c++");
break;
case ProjectFile::CSource:
opts += QLatin1String("c");
break;
case ProjectFile::ObjCHeader:
// opts += QLatin1String("objective-c-header");
// break;
case ProjectFile::ObjCXXHeader:
opts += QLatin1String("objective-c++-header");
break;
case ProjectFile::ObjCSource:
opts += QLatin1String("objective-c");
break;
case ProjectFile::ObjCXXSource:
opts += QLatin1String("objective-c++");
break;
case ProjectFile::OpenCLSource:
opts += QLatin1String("cl");
break;
case ProjectFile::CudaSource:
opts += QLatin1String("cuda");
break;
}
return opts;
}
} // namespace Utils
} // namespace Clang

View File

@@ -0,0 +1,58 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef CPPTOOLS_CLANGUTILS_H
#define CPPTOOLS_CLANGUTILS_H
#include "utils.h"
#include <cpptools/cppmodelmanagerinterface.h>
namespace ClangCodeModel {
namespace Utils {
ClangCodeModel::Internal::UnsavedFiles createUnsavedFiles(CppTools::CppModelManagerInterface::WorkingCopy workingCopy);
QStringList createClangOptions(const CppTools::ProjectPart::Ptr &pPart, CppTools::ProjectFile::Kind fileKind);
QStringList createClangOptions(const CppTools::ProjectPart::Ptr &pPart, const QString &fileName = QString());
QStringList clangNonProjectFileOptions(CppTools::ProjectFile::Kind kind);
QStringList createPCHInclusionOptions(const QStringList &pchFiles);
QStringList createPCHInclusionOptions(const QString &pchFile);
QStringList clangLanguageOption(CppTools::ProjectFile::Kind fileKind);
QStringList clangOptionsForC(CppTools::ProjectPart::CVersion cVersion,
CppTools::ProjectPart::CXXExtensions cxxExtensions);
QStringList clangOptionsForCxx(CppTools::ProjectPart::QtVersion qtVersion,
CppTools::ProjectPart::CXXVersion cxxVersion,
CppTools::ProjectPart::CXXExtensions cxxExtensions);
} // namespace Utils
} // namespace Clang
#endif // CPPTOOLS_CLANGUTILS_H

View File

@@ -0,0 +1,748 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "completionproposalsbuilder.h"
#include "utils_p.h"
#include <QTextDocument>
#include <QCoreApplication>
enum PriorityFixes {
PriorityFix_ExplicitDestructorCall = 10
};
namespace ClangCodeModel {
namespace {
struct ObjCMessagePart {
QString text;
int signatureLen; // length of "setScale:" in "setScale: 13"
ObjCMessagePart() : signatureLen(0) {}
ObjCMessagePart(const QString &signature, int &indentBonus)
: text(signature)
, signatureLen(signature.length() + indentBonus)
{
indentBonus = 0;
}
void addToSignature(const QString &signature)
{
text += signature;
signatureLen += signature.length();
}
};
} // anonymous namespace
/**
* @class ClangCodeModel::CompletionProposalsBuilder
* @brief Captures completion lists and than processes sequence of completion chunks
*
* Can produce several completion proposals for one CXCompletionResult, if and
* only if result contains chunks with kind 'Optional'
* Different proposals can have the same text, it's normal behavior.
*
* @note Unit tests are in \a clangcompletion_test.cpp
*
* @note Unresolved problems:
* Function hint not appear after space: "foo(1, ";
* Slot can have optional arguments, that produces 2 slots.
*
*/
CompletionProposalsBuilder::CompletionProposalsBuilder(QList<CodeCompletionResult> &results, quint64 contexts, bool isSignalSlotCompletion)
: m_results(results)
, m_contexts(contexts)
, m_isSignalSlotCompletion(isSignalSlotCompletion)
{
}
void CompletionProposalsBuilder::operator ()(const CXCompletionResult &cxResult)
{
resetWithResult(cxResult);
#if defined(CINDEX_VERSION) && (CINDEX_VERSION > 5)
const QString brief = Internal::getQString(clang_getCompletionBriefComment(cxResult.CompletionString));
if (!brief.isEmpty())
m_comment += QLatin1String("<b>Brief:</b> ") + Qt::escape(brief);
#endif
if (m_resultAvailability == CodeCompletionResult::Deprecated) {
m_comment += QLatin1String("<b>@note</b> ");
m_comment += QCoreApplication::translate("deprecated C++ symbol", "Is deprecated");
}
m_hint = QLatin1String("<p>");
switch (m_resultKind) {
case CodeCompletionResult::ObjCMessageCompletionKind:
concatChunksForObjectiveCMessage(cxResult);
break;
case CodeCompletionResult::ClassCompletionKind:
case CodeCompletionResult::NamespaceCompletionKind:
case CodeCompletionResult::EnumeratorCompletionKind:
concatChunksForNestedName(cxResult.CompletionString);
break;
case CodeCompletionResult::ClangSnippetKind:
concatChunksAsSnippet(cxResult.CompletionString);
break;
case CodeCompletionResult::SlotCompletionKind:
case CodeCompletionResult::SignalCompletionKind:
if (m_isSignalSlotCompletion)
concatSlotSignalSignature(cxResult.CompletionString);
else
concatChunksOnlyTypedText(cxResult.CompletionString);
break;
default:
concatChunksOnlyTypedText(cxResult.CompletionString);
break;
}
m_hint += QLatin1String("</p>");
m_hint += m_comment;
finalize();
foreach (const OptionalChunk &chunk, m_optionalChunks) {
m_hint.insert(chunk.positionInHint, chunk.hint);
finalize();
}
}
/**
* @return Internal ClangCodeModel's completion kind, that affects further postprocessing
*/
CodeCompletionResult::Kind CompletionProposalsBuilder::getKind(const CXCompletionResult &cxResult)
{
CXCompletionString complStr = cxResult.CompletionString;
CXCursorKind cursorKind = cxResult.CursorKind;
switch (cursorKind) {
case CXCursor_Constructor:
return CodeCompletionResult::ConstructorCompletionKind;
case CXCursor_Destructor:
return CodeCompletionResult::DestructorCompletionKind;
case CXCursor_CXXMethod: {
const unsigned numAnnotations = clang_getCompletionNumAnnotations(complStr);
bool isSignal = false, isSlot = false;
for (unsigned i = 0; i < numAnnotations && !isSignal && !isSlot; ++i) {
CXString cxAnn = clang_getCompletionAnnotation(complStr, i);
QString ann = Internal::getQString(cxAnn);
isSignal = ann == QLatin1String("qt_signal");
isSlot = ann == QLatin1String("qt_slot");
}
if (isSignal)
return CodeCompletionResult::SignalCompletionKind;
if (isSlot)
return CodeCompletionResult::SlotCompletionKind;
} // intentional fall-through!
case CXCursor_ConversionFunction:
case CXCursor_FunctionDecl:
case CXCursor_FunctionTemplate:
case CXCursor_MemberRef:
case CXCursor_MemberRefExpr:
return CodeCompletionResult::FunctionCompletionKind;
break;
case CXCursor_FieldDecl:
case CXCursor_VarDecl:
case CXCursor_ParmDecl:
case CXCursor_ObjCIvarDecl:
case CXCursor_ObjCPropertyDecl:
case CXCursor_ObjCSynthesizeDecl:
case CXCursor_NonTypeTemplateParameter:
return CodeCompletionResult::VariableCompletionKind;
case CXCursor_Namespace:
case CXCursor_NamespaceAlias:
case CXCursor_NamespaceRef:
return CodeCompletionResult::NamespaceCompletionKind;
case CXCursor_StructDecl:
case CXCursor_UnionDecl:
case CXCursor_ClassDecl:
case CXCursor_TypeRef:
case CXCursor_TemplateRef:
case CXCursor_TypedefDecl:
case CXCursor_ClassTemplate:
case CXCursor_ClassTemplatePartialSpecialization:
case CXCursor_ObjCClassRef:
case CXCursor_ObjCInterfaceDecl:
case CXCursor_ObjCImplementationDecl:
case CXCursor_ObjCCategoryDecl:
case CXCursor_ObjCCategoryImplDecl:
case CXCursor_ObjCProtocolDecl:
case CXCursor_ObjCProtocolRef:
case CXCursor_TemplateTypeParameter:
case CXCursor_TemplateTemplateParameter:
return CodeCompletionResult::ClassCompletionKind;
case CXCursor_EnumConstantDecl:
return CodeCompletionResult::EnumeratorCompletionKind;
case CXCursor_EnumDecl:
return CodeCompletionResult::EnumCompletionKind;
case CXCursor_MacroDefinition: {
const unsigned numChunks = clang_getNumCompletionChunks(complStr);
for (unsigned i = 0; i < numChunks; ++i) {
CXCompletionChunkKind kind = clang_getCompletionChunkKind(complStr, i);
if (kind == CXCompletionChunk_Placeholder) {
return CodeCompletionResult::FunctionCompletionKind;
}
}
return CodeCompletionResult::PreProcessorCompletionKind;
}
case CXCursor_PreprocessingDirective:
case CXCursor_MacroExpansion:
case CXCursor_InclusionDirective:
return CodeCompletionResult::PreProcessorCompletionKind;
case CXCursor_ObjCClassMethodDecl:
case CXCursor_ObjCInstanceMethodDecl:
return CodeCompletionResult::ObjCMessageCompletionKind;
case CXCursor_NotImplemented: {
const unsigned numChunks = clang_getNumCompletionChunks(complStr);
for (unsigned i = 0; i < numChunks; ++i) {
CXCompletionChunkKind kind = clang_getCompletionChunkKind(complStr, i);
if (kind == CXCompletionChunk_Placeholder) {
return CodeCompletionResult::ClangSnippetKind;
}
}
return CodeCompletionResult::KeywordCompletionKind;
}
default:
break;
}
return CodeCompletionResult::Other;
}
/**
* @return Symbol availability, which is almost unused
*/
CodeCompletionResult::Availability CompletionProposalsBuilder::getAvailability(const CXCompletionResult &cxResult)
{
CXCompletionString complStr = cxResult.CompletionString;
switch (clang_getCompletionAvailability(complStr)) {
case CXAvailability_Deprecated:
return CodeCompletionResult::Deprecated;
case CXAvailability_NotAvailable:
return CodeCompletionResult::NotAvailable;
case CXAvailability_NotAccessible:
return CodeCompletionResult::NotAccessible;
default:
return CodeCompletionResult::Available;
}
}
/**
* @return Start index of name, which is unused in Qt signal/slot signature
* @param text Text of Placeholder completion string chunk
*/
int CompletionProposalsBuilder::findNameInPlaceholder(const QString &text)
{
bool firstIdPassed = false;
bool isInIdentifier = false;
int bracesCounter = 0;
int idStart = 0;
for (int i = 0, n = text.size(); i < n; ++i) {
const QChar ch = text[i];
if (ch == QLatin1Char(':')) {
firstIdPassed = false;
isInIdentifier = false;
}
if (ch == QLatin1Char('<') || ch == QLatin1Char('(')) {
if (isInIdentifier && text.mid(idStart, i - idStart) == QLatin1String("const"))
firstIdPassed = false;
++bracesCounter;
isInIdentifier = false;
} else if (ch == QLatin1Char('>') || ch == QLatin1Char(')')) {
if (isInIdentifier && text.mid(idStart, i - idStart) == QLatin1String("const"))
firstIdPassed = false;
--bracesCounter;
isInIdentifier = false;
} else if (bracesCounter == 0) {
if (isInIdentifier) {
isInIdentifier = ch.isLetterOrNumber() || (ch == QLatin1Char('_'));
if (!isInIdentifier && text.mid(idStart, i - idStart) == QLatin1String("const"))
firstIdPassed = false;
} else if (ch.isLetter() || (ch == QLatin1Char('_'))) {
if (firstIdPassed)
return i;
isInIdentifier = true;
idStart = i;
firstIdPassed = true;
}
}
}
return text.size();
}
void CompletionProposalsBuilder::resetWithResult(const CXCompletionResult &cxResult)
{
m_priority = clang_getCompletionPriority(cxResult.CompletionString);
m_resultKind = getKind(cxResult);
m_resultAvailability = getAvailability(cxResult);
m_hasParameters = false;
m_hint.clear();
m_text.clear();
m_snippet.clear();
m_comment.clear();
m_optionalChunks.clear();
}
/**
* @brief Appends completion proposal initialized with collected data
*/
void CompletionProposalsBuilder::finalize()
{
// Fixes code completion: operator and destructor cases
if ((m_contexts & CXCompletionContext_DotMemberAccess)
|| (m_contexts & CXCompletionContext_ArrowMemberAccess)
|| (m_contexts & CXCompletionContext_AnyValue)) {
if (m_resultKind == CodeCompletionResult::DestructorCompletionKind)
m_priority *= PriorityFix_ExplicitDestructorCall;
else if (m_resultKind == CodeCompletionResult::FunctionCompletionKind
&& m_text.startsWith(QLatin1String("operator")))
return;
}
CodeCompletionResult ccr(m_priority);
ccr.setCompletionKind(m_resultKind);
ccr.setAvailability(m_resultAvailability);
ccr.setHasParameters(m_hasParameters);
ccr.setHint(m_hint);
ccr.setText(m_text);
ccr.setSnippet(m_snippet);
m_results.append(ccr);
}
/**
* @brief Creates text, hint and snippet
*
* Text is just signature, e.g. 'length' for [NSString length] or 'respondsToSelector:'
* for [id respondsToSelector:(SEL)sel].
* Snippet is actual text, where any message parameter becames snippet part:
* 'respondsToSelector:$(SEL)sel$'.
* Hint consists of snippet preview and doxygen 'return' entry with returned type.
*/
void CompletionProposalsBuilder::concatChunksForObjectiveCMessage(const CXCompletionResult &cxResult)
{
CXCompletionString cxString = cxResult.CompletionString;
const unsigned count = clang_getNumCompletionChunks(cxString);
unsigned index = 0;
QString hintPrefix;
if (cxResult.CursorKind == CXCursor_ObjCClassMethodDecl)
hintPrefix += QLatin1Char('+');
else
hintPrefix += QLatin1Char('-');
int indentBonus = 1;
bool addSpaceAtPrefixEnd = true;
for (; index < count; ++index) {
CXCompletionChunkKind chunkKind = clang_getCompletionChunkKind(cxString, index);
if (chunkKind == CXCompletionChunk_TypedText || chunkKind == CXCompletionChunk_Informative) {
break;
}
const QString text = Internal::getQString(clang_getCompletionChunkText(cxString, index), false);
if (chunkKind == CXCompletionChunk_ResultType) {
hintPrefix += QLatin1String("(");
hintPrefix += Qt::escape(text);
hintPrefix += QLatin1String(") ");
indentBonus += 3 + text.length();
addSpaceAtPrefixEnd = false;
} else {
hintPrefix += Qt::escape(text);
indentBonus += text.length();
m_snippet += text;
}
}
if (addSpaceAtPrefixEnd) {
m_snippet += QLatin1Char(' ');
hintPrefix += QLatin1Char(' ');
indentBonus += 1;
}
m_hint += hintPrefix;
QList<ObjCMessagePart> parts;
bool previousWasTypedText = false;
for (; index < count; ++index) {
CXCompletionChunkKind chunkKind = clang_getCompletionChunkKind(cxString, index);
const QString text = Internal::getQString(clang_getCompletionChunkText(cxString, index), false);
switch (chunkKind) {
case CXCompletionChunk_TypedText:
if (previousWasTypedText)
parts.back().addToSignature(text);
else
parts.append(ObjCMessagePart(text, indentBonus));
m_snippet += text;
m_text += text;
break;
case CXCompletionChunk_Informative:
parts.append(ObjCMessagePart(text, indentBonus));
break;
case CXCompletionChunk_Text:
case CXCompletionChunk_LeftParen:
case CXCompletionChunk_RightParen:
case CXCompletionChunk_Comma:
case CXCompletionChunk_HorizontalSpace:
m_snippet += text;
parts.back().text += Qt::escape(text);
break;
case CXCompletionChunk_Placeholder:
appendSnippet(text);
parts.back().text += QLatin1String("<b>");
parts.back().text += Qt::escape(text);
parts.back().text += QLatin1String("</b>");
break;
case CXCompletionChunk_LeftAngle:
m_snippet += text;
parts.back().text += QLatin1String("&lt;");
break;
case CXCompletionChunk_RightAngle:
m_snippet += text;
parts.back().text += QLatin1String("&gt;");
break;
default:
break;
}
previousWasTypedText = (chunkKind == CXCompletionChunk_TypedText);
}
int indent = 0;
foreach (const ObjCMessagePart &part, parts)
indent = qMax(indent, part.signatureLen);
bool isFirstPart = true;
foreach (const ObjCMessagePart &part, parts) {
if (!isFirstPart)
m_hint += QLatin1String("<br/>");
isFirstPart = false;
for (int i = 0; i < indent - part.signatureLen; ++i)
m_hint += QLatin1String("&nbsp;");
m_hint += part.text;
}
}
/**
* @brief Creates entries like 'MyClass', 'MyNamespace::', 'MyEnumClass::Value1'
*/
void CompletionProposalsBuilder::concatChunksForNestedName(const CXCompletionString &cxString)
{
bool hasPlaceholder = false;
unsigned count = clang_getNumCompletionChunks(cxString);
for (unsigned i = 0; i < count; ++i) {
CXCompletionChunkKind chunkKind = clang_getCompletionChunkKind(cxString, i);
QString text = Internal::getQString(clang_getCompletionChunkText(cxString, i), false);
switch (chunkKind) {
case CXCompletionChunk_TypedText:
case CXCompletionChunk_Text:
m_text += text;
m_snippet += text;
m_hint += text;
break;
case CXCompletionChunk_LeftAngle:
case CXCompletionChunk_RightAngle:
case CXCompletionChunk_Comma:
case CXCompletionChunk_HorizontalSpace:
m_snippet += text;
m_hint += Qt::escape(text);
break;
case CXCompletionChunk_Placeholder:
hasPlaceholder = true;
appendSnippet(text);
appendHintBold(text);
break;
default:
break;
}
}
if (!hasPlaceholder)
m_snippet.clear();
}
/**
* @brief Creates text, snippet and hint for snippet preview
*
* Text is copy of snippet without '$' marks.
* Hint also have 'return' doxygen entry if applicable (e.g. 'typeid...')
*/
void CompletionProposalsBuilder::concatChunksAsSnippet(const CXCompletionString &cxString)
{
unsigned count = clang_getNumCompletionChunks(cxString);
for (unsigned i = 0; i < count; ++i) {
CXCompletionChunkKind chunkKind = clang_getCompletionChunkKind(cxString, i);
const QString text = Internal::getQString(clang_getCompletionChunkText(cxString, i), false);
switch (chunkKind) {
case CXCompletionChunk_ResultType:
attachResultTypeToComment(text);
break;
case CXCompletionChunk_Placeholder:
m_text += text;
appendSnippet(text);
appendHintBold(text);
break;
case CXCompletionChunk_LeftAngle:
m_snippet += text;
m_text += text;
m_hint += QLatin1String("&lt;");
break;
case CXCompletionChunk_RightAngle:
m_snippet += text;
m_text += text;
m_hint += QLatin1String("&gt;");
break;
case CXCompletionChunk_VerticalSpace:
m_snippet += QLatin1Char('\n');
m_text += QLatin1Char(' ');
m_hint += QLatin1String("<br/>");
break;
default:
m_snippet += text;
m_text += text;
m_hint += text;
break;
}
}
}
/**
* @brief Creates short text and hint with details
*
* Text is just function or variable name. Hint also contains function signature
* or variable type.
*/
void CompletionProposalsBuilder::concatChunksOnlyTypedText(const CXCompletionString &cxString)
{
bool previousChunkWasLParen = false;
bool isInsideTemplateSpec = false;
unsigned count = clang_getNumCompletionChunks(cxString);
for (unsigned i = 0; i < count; ++i) {
CXCompletionChunkKind chunkKind = clang_getCompletionChunkKind(cxString, i);
QString text = Internal::getQString(clang_getCompletionChunkText(cxString, i), false);
switch (chunkKind) {
case CXCompletionChunk_LeftParen:
case CXCompletionChunk_RightParen:
case CXCompletionChunk_Text:
case CXCompletionChunk_LeftAngle:
case CXCompletionChunk_RightAngle:
m_hint += Qt::escape(text);
break;
case CXCompletionChunk_HorizontalSpace:
case CXCompletionChunk_Comma:
if (isInsideTemplateSpec) {
m_snippet += text;
}
m_hint += Qt::escape(text);
break;
case CXCompletionChunk_Placeholder:
if (isInsideTemplateSpec) {
appendSnippet(text);
}
m_hint += Qt::escape(text);
break;
case CXCompletionChunk_TypedText:
m_text = text;
appendHintBold(text);
break;
case CXCompletionChunk_ResultType: {
m_hint += Qt::escape(text);
QChar last = text[text.size() - 1];
if (last != QLatin1Char('*') && last != QLatin1Char('&'))
m_hint += QLatin1Char(' ');
}
break;
case CXCompletionChunk_Informative:
if (text == QLatin1String(" const"))
m_hint += text;
break;
case CXCompletionChunk_Optional:
appendOptionalChunks(clang_getCompletionChunkCompletionString(cxString, i),
m_hint.size());
break;
default:
break;
}
if (chunkKind == CXCompletionChunk_RightParen && previousChunkWasLParen)
m_hasParameters = false;
if (chunkKind == CXCompletionChunk_LeftParen) {
previousChunkWasLParen = true;
m_hasParameters = true;
} else {
previousChunkWasLParen = false;
}
if (chunkKind == CXCompletionChunk_LeftAngle) {
m_snippet = m_text;
m_snippet += text;
isInsideTemplateSpec = true;
} else if (chunkKind == CXCompletionChunk_RightAngle) {
isInsideTemplateSpec = false;
m_snippet += text;
}
}
}
/**
* @brief Produces signal/slot signatures for 'connect' methods family
*/
void CompletionProposalsBuilder::concatSlotSignalSignature(const CXCompletionString &cxString)
{
QString resultType;
unsigned count = clang_getNumCompletionChunks(cxString);
for (unsigned i = 0; i < count; ++i) {
CXCompletionChunkKind chunkKind = clang_getCompletionChunkKind(cxString, i);
QString text = Internal::getQString(clang_getCompletionChunkText(cxString, i), false);
switch (chunkKind) {
case CXCompletionChunk_Placeholder:
text.truncate(findNameInPlaceholder(text));
// fall-through
case CXCompletionChunk_TypedText:
case CXCompletionChunk_LeftParen:
case CXCompletionChunk_RightParen:
case CXCompletionChunk_Comma:
case CXCompletionChunk_Text:
m_text += text;
break;
case CXCompletionChunk_ResultType:
resultType += text;
resultType += QLatin1Char(' ');
break;
default:
break;
}
}
const QString parent = Internal::getQString(clang_getCompletionParent(cxString, NULL));
if (m_resultKind == CodeCompletionResult::SlotCompletionKind)
m_hint += QObject::tr("Slot of %1, returns %2").arg(parent).arg(resultType);
else
m_hint += QObject::tr("Signal of %1, returns %2").arg(parent).arg(resultType);
}
/**
* @brief Stores optional part for further postprocessing in \a finalize()
* @param insertionIndex Index where to insert optional chunk into hint
*/
void CompletionProposalsBuilder::appendOptionalChunks(const CXCompletionString &cxString,
int insertionIndex)
{
OptionalChunk chunk;
chunk.positionInHint = insertionIndex;
unsigned count = clang_getNumCompletionChunks(cxString);
for (unsigned i = 0; i < count; ++i) {
CXCompletionChunkKind chunkKind = clang_getCompletionChunkKind(cxString, i);
QString text = Internal::getQString(clang_getCompletionChunkText(cxString, i), false);
switch (chunkKind) {
case CXCompletionChunk_Placeholder:
chunk.hint += Qt::escape(text);
break;
case CXCompletionChunk_Comma:
chunk.hint += text;
chunk.hint += QLatin1Char(' ');
break;
case CXCompletionChunk_Optional:
m_optionalChunks.append(chunk);
appendOptionalChunks(clang_getCompletionChunkCompletionString(cxString, i),
insertionIndex + chunk.hint.size());
return;
default:
break;
}
}
m_optionalChunks.append(chunk);
}
void CompletionProposalsBuilder::attachResultTypeToComment(const QString &resultType)
{
if (resultType.isEmpty())
return;
if (!m_comment.isEmpty())
m_comment += QLatin1String("<br/>");
m_comment += QLatin1String("<b>@return</b> ");
m_comment += resultType;
}
void CompletionProposalsBuilder::appendSnippet(const QString &text)
{
m_snippet += QLatin1Char('$');
m_snippet += text;
m_snippet += QLatin1Char('$');
}
void CompletionProposalsBuilder::appendHintBold(const QString &text)
{
m_hint += QLatin1String("<b>");
m_hint += Qt::escape(text);
m_hint += QLatin1String("</b>");
}
} // namespace ClangCodeModel

View File

@@ -0,0 +1,88 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef CLANGCODEMODEL_COMPLETIONPROPOSALSBUILDER_H
#define CLANGCODEMODEL_COMPLETIONPROPOSALSBUILDER_H
#include "clangcompleter.h"
#include "clang_global.h"
#include <clang-c/Index.h>
namespace ClangCodeModel {
class CLANG_EXPORT CompletionProposalsBuilder
{
public:
CompletionProposalsBuilder(QList<CodeCompletionResult> &results, quint64 contexts, bool isSignalSlotCompletion);
void operator ()(const CXCompletionResult &cxResult);
private:
struct OptionalChunk {
int positionInHint;
QString hint;
OptionalChunk() : positionInHint(0) {}
};
static CodeCompletionResult::Kind getKind(const CXCompletionResult &cxResult);
static CodeCompletionResult::Availability getAvailability(const CXCompletionResult &cxResult);
static int findNameInPlaceholder(const QString &text);
void resetWithResult(const CXCompletionResult &cxResult);
void finalize();
void concatChunksForObjectiveCMessage(const CXCompletionResult &cxResult);
void concatChunksForNestedName(const CXCompletionString &cxString);
void concatChunksAsSnippet(const CXCompletionString &cxString);
void concatChunksOnlyTypedText(const CXCompletionString &cxString);
void concatSlotSignalSignature(const CXCompletionString &cxString);
void appendOptionalChunks(const CXCompletionString &cxString,
int insertionIndex);
void attachResultTypeToComment(const QString &text);
void appendSnippet(const QString &text);
void appendHintBold(const QString &text);
QList<CodeCompletionResult> &m_results;
const quint64 m_contexts;
const bool m_isSignalSlotCompletion;
unsigned m_priority;
CodeCompletionResult::Kind m_resultKind;
CodeCompletionResult::Availability m_resultAvailability;
bool m_hasParameters;
QString m_hint;
QString m_text;
QString m_snippet;
QString m_comment;
QList<OptionalChunk> m_optionalChunks;
};
} // namespace ClangCodeModel
#endif // CLANGCODEMODEL_COMPLETIONPROPOSALSBUILDER_H

View File

@@ -0,0 +1,61 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef CONSTANTS_H
#define CONSTANTS_H
#include <QtCore/QLatin1Char>
#include <QtCore/QLatin1Char>
namespace ClangCodeModel {
namespace Constants {
static const QLatin1Char kLParen('(');
static const QLatin1Char kRParen(')');
static const QLatin1Char kLBrace('{');
static const QLatin1Char kRBrace('}');
static const QLatin1Char kLBracket('[');
static const QLatin1Char kRBracket(']');
static const QLatin1Char kLABracket('<');
static const QLatin1Char kRABracket('>');
static const QLatin1Char kSemiColon(';');
static const QLatin1Char kPound('#');
static const QLatin1Char kColon(':');
static const QLatin1Char kExclamation('!');
static const QLatin1Char kSpace(' ');
static const QLatin1Char kSlash('/');
static const QLatin1Char kStar('*');
static const QLatin1Char kDoubleQuote('"');
static const QLatin1Char kNewLine('\n');
static const QLatin1Char kHorizontalTab('\t');
}
}
#endif // CONSTANTS_H

View File

@@ -0,0 +1,201 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "clangutils.h"
#include "cppcreatemarkers.h"
#include <cplusplus/CppDocument.h>
#include <cpptools/cppmodelmanagerinterface.h>
#include <utils/runextensions.h>
#include <QCoreApplication>
#include <QMutexLocker>
#include <QThreadPool>
#include <QDebug>
static const bool DebugTiming = !qgetenv("QTC_CLANG_VERBOSE").isEmpty();
using namespace ClangCodeModel;
using namespace ClangCodeModel::Internal;
using namespace CppTools;
CreateMarkers *CreateMarkers::create(SemanticMarker::Ptr semanticMarker,
const QString &fileName,
const QStringList &options,
unsigned firstLine, unsigned lastLine,
FastIndexer *fastIndexer,
const Internal::PchInfo::Ptr &pchInfo)
{
if (semanticMarker.isNull())
return 0;
else
return new CreateMarkers(semanticMarker, fileName, options, firstLine, lastLine, fastIndexer, pchInfo);
}
CreateMarkers::CreateMarkers(SemanticMarker::Ptr semanticMarker,
const QString &fileName,
const QStringList &options,
unsigned firstLine, unsigned lastLine,
FastIndexer *fastIndexer,
const Internal::PchInfo::Ptr &pchInfo)
: m_marker(semanticMarker)
, m_pchInfo(pchInfo)
, m_fileName(fileName)
, m_options(options)
, m_firstLine(firstLine)
, m_lastLine(lastLine)
, m_fastIndexer(fastIndexer)
{
Q_ASSERT(!semanticMarker.isNull());
m_flushRequested = false;
m_flushLine = 0;
m_unsavedFiles = Utils::createUnsavedFiles(CppModelManagerInterface::instance()->workingCopy());
}
CreateMarkers::~CreateMarkers()
{ }
void CreateMarkers::run()
{
QMutexLocker lock(m_marker->mutex());
if (isCanceled())
return;
m_options += QLatin1String("-fspell-checking");
QTime t;
if (DebugTiming) {
qDebug() << "*** Highlighting from" << m_firstLine << "to" << m_lastLine << "of" << m_fileName;
qDebug() << "***** Options: " << m_options.join(QLatin1String(" "));
t.start();
}
m_usages.clear();
m_marker->setFileName(m_fileName);
m_marker->setCompilationOptions(m_options);
m_marker->reparse(m_unsavedFiles);
if (DebugTiming)
qDebug() << "*** Reparse for highlighting took" << t.elapsed() << "ms.";
m_pchInfo.clear();
typedef CPlusPlus::Document::DiagnosticMessage OtherDiagnostic;
QList<OtherDiagnostic> msgs;
foreach (const ClangCodeModel::Diagnostic &d, m_marker->diagnostics()) {
if (DebugTiming)
qDebug() << d.severityAsString() << d.location() << d.spelling();
if (d.location().fileName() != m_marker->fileName())
continue;
// TODO: retrieve fix-its for this diagnostic
int level;
switch (d.severity()) {
case Diagnostic::Fatal: level = OtherDiagnostic::Fatal; break;
case Diagnostic::Error: level = OtherDiagnostic::Error; break;
case Diagnostic::Warning: level = OtherDiagnostic::Warning; break;
default: continue;
}
msgs.append(OtherDiagnostic(level, d.location().fileName(), d.location().line(),
d.location().column(), d.spelling(), d.length()));
}
if (isCanceled()) {
reportFinished();
return;
}
CppModelManagerInterface *mmi = CppModelManagerInterface::instance();
static const QString key = QLatin1String("ClangCodeModel.Diagnostics");
mmi->setExtraDiagnostics(m_marker->fileName(), key, msgs);
#if CINDEX_VERSION_MINOR >= 21
mmi->setIfdefedOutBlocks(m_marker->fileName(), m_marker->ifdefedOutBlocks());
#endif
if (isCanceled()) {
reportFinished();
return;
}
QList<ClangCodeModel::SourceMarker> markers = m_marker->sourceMarkersInRange(m_firstLine, m_lastLine);
foreach (const ClangCodeModel::SourceMarker &m, markers)
addUse(SourceMarker(m.location().line(), m.location().column(), m.length(), m.kind()));
if (isCanceled()) {
reportFinished();
return;
}
flush();
reportFinished();
if (DebugTiming) {
qDebug() << "*** Highlighting took" << t.elapsed() << "ms in total.";
t.restart();
}
if (m_fastIndexer)
m_fastIndexer->indexNow(m_marker->unit());
if (DebugTiming)
qDebug() << "*** Fast re-indexing took" << t.elapsed() << "ms in total.";
}
void CreateMarkers::addUse(const SourceMarker &marker)
{
// if (! enclosingFunctionDefinition()) {
if (m_usages.size() >= 100) {
if (m_flushRequested && marker.line != m_flushLine)
flush();
else if (! m_flushRequested) {
m_flushRequested = true;
m_flushLine = marker.line;
}
}
// }
m_usages.append(marker);
}
void CreateMarkers::flush()
{
m_flushRequested = false;
m_flushLine = 0;
if (m_usages.isEmpty())
return;
reportResults(m_usages);
m_usages.clear();
}

View File

@@ -0,0 +1,106 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef CPPCREATEMARKERS_H
#define CPPCREATEMARKERS_H
#include "fastindexer.h"
#include "sourcemarker.h"
#include "semanticmarker.h"
#include "pchinfo.h"
#include <texteditor/semantichighlighter.h>
#include <QSet>
#include <QFuture>
#include <QtConcurrentRun>
namespace ClangCodeModel {
class CreateMarkers:
public QObject,
public QRunnable,
public QFutureInterface<TextEditor::HighlightingResult>
{
Q_OBJECT
Q_DISABLE_COPY(CreateMarkers)
public:
virtual ~CreateMarkers();
virtual void run();
typedef TextEditor::HighlightingResult SourceMarker;
typedef QFuture<SourceMarker> Future;
Future start()
{
this->setRunnable(this);
this->reportStarted();
Future future = this->future();
QThreadPool::globalInstance()->start(this, QThread::LowestPriority);
return future;
}
static CreateMarkers *create(ClangCodeModel::SemanticMarker::Ptr semanticMarker,
const QString &fileName,
const QStringList &options,
unsigned firstLine, unsigned lastLine,
Internal::FastIndexer *fastIndexer,
const Internal::PchInfo::Ptr &pchInfo);
void addUse(const SourceMarker &marker);
void flush();
protected:
CreateMarkers(ClangCodeModel::SemanticMarker::Ptr semanticMarker,
const QString &fileName, const QStringList &options,
unsigned firstLine, unsigned lastLine,
Internal::FastIndexer *fastIndexer,
const Internal::PchInfo::Ptr &pchInfo);
private:
ClangCodeModel::SemanticMarker::Ptr m_marker;
Internal::PchInfo::Ptr m_pchInfo;
QString m_fileName;
QStringList m_options;
unsigned m_firstLine;
unsigned m_lastLine;
Internal::FastIndexer *m_fastIndexer;
QVector<SourceMarker> m_usages;
bool m_flushRequested;
unsigned m_flushLine;
ClangCodeModel::Internal::UnsavedFiles m_unsavedFiles;
};
} // namespace ClangCodeModel
#endif // CPPCREATEMARKERS_H

View File

@@ -0,0 +1,550 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "cxprettyprinter.h"
#include "utils_p.h"
#include "cxraii.h"
#include <QStringList>
using namespace ClangCodeModel;
using namespace ClangCodeModel::Internal;
CXPrettyPrinter::CXPrettyPrinter()
: m_indent(0)
{
}
QString CXPrettyPrinter::toString(CXCompletionChunkKind kind) const
{
switch (kind) {
case CXCompletionChunk_Optional:
return QLatin1String("Optional");
case CXCompletionChunk_TypedText:
return QLatin1String("TypedText");
case CXCompletionChunk_Text:
return QLatin1String("Text");
case CXCompletionChunk_Placeholder:
return QLatin1String("Placeholder");
case CXCompletionChunk_Informative:
return QLatin1String("Informative");
case CXCompletionChunk_CurrentParameter:
return QLatin1String("CurrentParameter");
case CXCompletionChunk_LeftParen:
return QLatin1String("LeftParen");
case CXCompletionChunk_RightParen:
return QLatin1String("RightParen");
case CXCompletionChunk_LeftBracket:
return QLatin1String("LeftBracket");
case CXCompletionChunk_RightBracket:
return QLatin1String("RightBracket");
case CXCompletionChunk_LeftBrace:
return QLatin1String("LeftBrace");
case CXCompletionChunk_RightBrace:
return QLatin1String("RightBrace");
case CXCompletionChunk_LeftAngle:
return QLatin1String("LeftAngle");
case CXCompletionChunk_RightAngle:
return QLatin1String("RightAngle");
case CXCompletionChunk_Comma:
return QLatin1String("Comma");
case CXCompletionChunk_ResultType:
return QLatin1String("ResultType");
case CXCompletionChunk_Colon:
return QLatin1String("Colon");
case CXCompletionChunk_SemiColon:
return QLatin1String("SemiColon");
case CXCompletionChunk_Equal:
return QLatin1String("Equal");
case CXCompletionChunk_HorizontalSpace:
return QLatin1String("HorizontalSpace");
case CXCompletionChunk_VerticalSpace:
return QLatin1String("VerticalSpace");
default:
return QLatin1String("<UNKNOWN>");
}
}
QString CXPrettyPrinter::toString(CXAvailabilityKind kind) const
{
switch (kind) {
case CXAvailability_Available:
return QLatin1String("Available");
case CXAvailability_Deprecated:
return QLatin1String("Deprecated");
case CXAvailability_NotAccessible:
return QLatin1String("NotAccessible");
case CXAvailability_NotAvailable:
return QLatin1String("NotAvailable");
default:
return QLatin1String("<UNKNOWN>");
}
}
QString CXPrettyPrinter::toString(CXCursorKind kind) const
{
return getQString(clang_getCursorKindSpelling(kind));
}
QString CXPrettyPrinter::toString(CXDiagnosticSeverity severity) const
{
switch (severity)
{
case CXDiagnostic_Ignored:
return QLatin1String("Ignored");
case CXDiagnostic_Note:
return QLatin1String("Note");
case CXDiagnostic_Warning:
return QLatin1String("Warning");
case CXDiagnostic_Error:
return QLatin1String("Error");
case CXDiagnostic_Fatal:
return QLatin1String("Fatal");
default:
return QLatin1String("<UNKNOWN>");
}
}
QString CXPrettyPrinter::jsonForCompletionMeta(CXCodeCompleteResults *results)
{
QString json;
m_printed.swap(json);
m_indent = 0;
m_printed += QLatin1String("CXCodeCompleteResults {");
m_indent += 4;
CXCursorKind containerKind = clang_codeCompleteGetContainerKind(results, NULL);
writeLineEnd();
m_printed += QLatin1String("'container CursorKind': ");
m_printed += toString(containerKind);
m_printed += QLatin1Char(',');
QString containerUSR(Internal::getQString(clang_codeCompleteGetContainerUSR(results)));
if (!containerUSR.isEmpty()) {
writeLineEnd();
m_printed += QLatin1String("'container USR': ");
m_printed += containerUSR;
m_printed += QLatin1Char(',');
}
QString objCSelector(Internal::getQString(clang_codeCompleteGetObjCSelector(results)));
if (!objCSelector.isEmpty()) {
writeLineEnd();
m_printed += QLatin1String("'Objective-C selector': ");
m_printed += objCSelector;
m_printed += QLatin1Char(',');
}
writeLineEnd();
m_printed += QLatin1String("'contexts': [");
m_indent += 4;
writeCompletionContexts(results);
m_indent -= 4;
writeLineEnd();
m_printed += QLatin1Char(']');
m_indent -= 4;
writeLineEnd();
m_printed += QLatin1Char('}');
m_printed.swap(json);
return json;
}
QString CXPrettyPrinter::jsonForCompletionString(const CXCompletionString &string)
{
QString json;
m_printed.swap(json);
m_indent = 0;
m_printed += QLatin1String("CXCompletionString: ");
writeCompletionStringJson(string);
m_printed.swap(json);
return json;
}
QString CXPrettyPrinter::jsonForCompletion(const CXCompletionResult &result)
{
QString json;
m_printed.swap(json);
m_indent = 4;
m_printed += QLatin1String("CXCompletionResult: {\n"
" CompletionString: ");
writeCompletionStringJson(result.CompletionString);
m_printed += QLatin1Char('\n');
m_printed += QLatin1String(" CursorKind: ");
m_printed += toString(result.CursorKind);
m_printed += QLatin1String(";\n}");
m_printed.swap(json);
return json;
}
/**
* @brief CXPrettyPrinter::jsonForDiagnsotic
* @param diagnostic
* @return
*
* List of used clang-c API calls:
* CXDiagnosticSet clang_getChildDiagnostics(CXDiagnostic D);
* CXSourceLocation clang_getDiagnosticLocation(CXDiagnostic);
* CXString clang_getDiagnosticOption(CXDiagnostic Diag,
* CXString *Disable);
* unsigned clang_getDiagnosticCategory(CXDiagnostic);
* CXString clang_getDiagnosticCategoryText(CXDiagnostic);
* unsigned clang_getDiagnosticNumRanges(CXDiagnostic);
* CXSourceRange clang_getDiagnosticRange(CXDiagnostic Diagnostic,
* unsigned Range);
* unsigned clang_getDiagnosticNumFixIts(CXDiagnostic Diagnostic);
* CXString clang_getDiagnosticFixIt(CXDiagnostic Diagnostic,
* unsigned FixIt,
* CXSourceRange *ReplacementRange);
*/
QString CXPrettyPrinter::jsonForDiagnsotic(const CXDiagnostic &diagnostic)
{
QString json;
m_printed.swap(json);
m_indent = 0;
m_printed += QLatin1String("CXDiagnostic: ");
writeDiagnosticJson(diagnostic);
m_printed.swap(json);
return json;
}
void CXPrettyPrinter::writeCompletionContexts(CXCodeCompleteResults *results)
{
quint64 contexts = clang_codeCompleteGetContexts(results);
QStringList lines;
if (contexts & CXCompletionContext_AnyType)
lines << QLatin1String("'any type'");
if (contexts & CXCompletionContext_AnyValue)
lines << QLatin1String("'any value'");
if (contexts & CXCompletionContext_ObjCObjectValue)
lines << QLatin1String("'Objective-C object'");
if (contexts & CXCompletionContext_ObjCSelectorValue)
lines << QLatin1String("'Objective-C selector'");
if (contexts & CXCompletionContext_CXXClassTypeValue)
lines << QLatin1String("'C++ class'");
if (contexts & CXCompletionContext_DotMemberAccess)
lines << QLatin1String("'. member access'");
if (contexts & CXCompletionContext_ArrowMemberAccess)
lines << QLatin1String("'-> member access'");
if (contexts & CXCompletionContext_ObjCPropertyAccess)
lines << QLatin1String("'. Objective-C property access'");
if (contexts & CXCompletionContext_EnumTag)
lines << QLatin1String("'enum tag'");
if (contexts & CXCompletionContext_UnionTag)
lines << QLatin1String("'union tag'");
if (contexts & CXCompletionContext_StructTag)
lines << QLatin1String("'struct tag'");
if (contexts & CXCompletionContext_ClassTag)
lines << QLatin1String("'C++ class tag'");
if (contexts & CXCompletionContext_Namespace)
lines << QLatin1String("'namespace tag'");
if (contexts & CXCompletionContext_NestedNameSpecifier)
lines << QLatin1String("'C++ nested name specifier'");
if (contexts & CXCompletionContext_ObjCInterface)
lines << QLatin1String("'Objective-C interface'");
if (contexts & CXCompletionContext_ObjCProtocol)
lines << QLatin1String("'Objective-C protocol'");
if (contexts & CXCompletionContext_ObjCCategory)
lines << QLatin1String("'Objective-C category'");
if (contexts & CXCompletionContext_ObjCInstanceMessage)
lines << QLatin1String("'Objective-C instance message'");
if (contexts & CXCompletionContext_ObjCClassMessage)
lines << QLatin1String("'Objective-C class message'");
if (contexts & CXCompletionContext_ObjCSelectorName)
lines << QLatin1String("'Objective-C selector name'");
if (contexts & CXCompletionContext_MacroName)
lines << QLatin1String("'macro name'");
if (contexts & CXCompletionContext_NaturalLanguage)
lines << QLatin1String("'natural language'");
foreach (const QString &line, lines) {
writeLineEnd();
m_printed += line + QLatin1String(",");
}
}
void CXPrettyPrinter::writeCompletionStringJson(const CXCompletionString &string)
{
m_printed += QLatin1Char('{');
writeLineEnd();
// availability
m_printed += QLatin1String("availability: ");
m_printed += toString(clang_getCompletionAvailability(string));
m_printed += QLatin1Char(';');
writeLineEnd();
// priority
m_printed += QLatin1String("priority: ");
m_printed += QString::number(clang_getCompletionPriority(string));
m_printed += QLatin1Char(';');
writeLineEnd();
// parent
m_printed += QLatin1String("parent: \'");
m_printed += getQString(clang_getCompletionParent(string, NULL));
m_printed += QLatin1String("\';");
writeLineEnd();
// chunks
m_printed += QLatin1String("chunks: [");
m_indent += 4;
unsigned numChunks = clang_getNumCompletionChunks(string);
for (unsigned i = 0; i < numChunks; ++i) {
writeLineEnd();
writeCompletionChunkJson(string, i);
}
m_indent -= 4;
writeLineEnd();
m_printed += QLatin1Char(']');
writeLineEnd();
// annotation
m_printed += QLatin1String("annotations: [");
m_indent += 4;
unsigned numAnns = clang_getCompletionNumAnnotations(string);
for (unsigned i = 0; i < numAnns; ++i) {
writeLineEnd();
writeCompletionAnnotationJson(string, i);
}
m_indent -= 4;
writeLineEnd();
m_printed += QLatin1Char(']');
writeLineEnd();
m_printed += QLatin1Char('}');
}
void CXPrettyPrinter::writeCompletionChunkJson(const CXCompletionString &string, unsigned i)
{
QString text = getQString(clang_getCompletionChunkText(string, i));
QString kind = toString(clang_getCompletionChunkKind(string, i));
CXCompletionString optional = clang_getCompletionChunkCompletionString(string, i);
m_printed += kind;
m_printed += QLatin1String(": ");
if (!text.isEmpty()) {
m_printed += QLatin1Char('\'');
m_printed += text;
m_printed += QLatin1Char('\'');
}
if (optional != NULL) {
if (!text.isEmpty())
m_printed += QLatin1String(", ");
m_indent += 4;
writeCompletionStringJson(optional);
m_indent -= 4;
}
}
void CXPrettyPrinter::writeCompletionAnnotationJson(const CXCompletionString &string, unsigned i)
{
m_printed += QLatin1Char('\'');
m_printed += getQString(clang_getCompletionAnnotation(string, i));
m_printed += QLatin1Char('\'');
}
void CXPrettyPrinter::writeDiagnosticJson(const CXDiagnostic &diag)
{
m_printed += QLatin1String("{");
m_indent += 4;
writeLineEnd();
// message
m_printed += QLatin1Char('\'');
m_printed += getQString(clang_formatDiagnostic(diag, /*options*/ 0));
m_printed += QLatin1Char('\'');
writeLineEnd();
// severity
m_printed += QLatin1String("severity: ");
m_printed += toString(clang_getDiagnosticSeverity(diag));
writeLineEnd();
// location
m_printed += QLatin1String("location: ");
writeLocationJson(clang_getDiagnosticLocation(diag));
writeLineEnd();
// fix-its
unsigned numFixIts = clang_getDiagnosticNumFixIts(diag);
if (numFixIts > 0) {
m_printed += QLatin1String("FixIts: [");
writeLineEnd();
for (unsigned i = 0; i < numFixIts; ++i) {
writeFixItJson(diag, i);
writeLineEnd();
}
m_printed += QLatin1String("]");
writeLineEnd();
}
// clang CLI options
CXString cxDisabler;
QString enabler = getQString(clang_getDiagnosticOption(diag, &cxDisabler));
QString disabler = getQString(cxDisabler);
if (!enabler.isEmpty()) {
m_printed += QLatin1String("enabledBy: \'");
m_printed += enabler;
m_printed += QLatin1String("';");
writeLineEnd();
}
if (!disabler.isEmpty()) {
m_printed += QLatin1String("disabledBy: \'");
m_printed += disabler;
m_printed += QLatin1String("';");
writeLineEnd();
}
// diagnostic category
m_printed += QLatin1String("category: \'");
m_printed += getQString(clang_getDiagnosticCategoryText(diag));
m_printed += QLatin1String("';");
// ranges
unsigned numRanges = clang_getDiagnosticNumRanges(diag);
if (numRanges > 0) {
writeLineEnd();
m_printed += QLatin1String("ranges: [");
m_indent += 4;
for (unsigned i = 0; i < numRanges; ++i) {
writeLineEnd();
writeRangeJson(clang_getDiagnosticRange(diag, i));
}
m_indent -= 4;
writeLineEnd();
m_printed += QLatin1String("]");
}
// children
CXDiagnosticSet set(clang_getChildDiagnostics(diag));
unsigned numChildren = clang_getNumDiagnosticsInSet(set);
if (numChildren > 0) {
writeLineEnd();
m_printed += QLatin1String("children: [");
m_indent += 4;
for (unsigned i = 0; i < numChildren; ++i) {
writeLineEnd();
ScopedCXDiagnostic child(clang_getDiagnosticInSet(set, i));
writeDiagnosticJson(child);
}
m_indent -= 4;
writeLineEnd();
m_printed += QLatin1String("]");
}
m_indent -= 4;
writeLineEnd();
m_printed += QLatin1String("}");
}
void CXPrettyPrinter::writeFixItJson(const CXDiagnostic &diag, unsigned i)
{
CXSourceRange range; // half-open range [a, b)
QString text = getQString(clang_getDiagnosticFixIt(diag, i, &range));
m_printed += QLatin1String("{ newText: ");
m_printed += QLatin1String("\'");
m_printed += text;
m_printed += QLatin1String("\', range: ");
writeRangeJson(range);
m_printed += QLatin1String("}");
}
void CXPrettyPrinter::writeRangeJson(const CXSourceRange &range)
{
SourceLocation start = getSpellingLocation(clang_getRangeStart(range));
SourceLocation end = getSpellingLocation(clang_getRangeEnd(range));
m_printed += QLatin1Char('{');
m_indent += 4;
writeLineEnd();
m_printed += QLatin1String("file: \'");
m_printed += start.fileName();
m_printed += QLatin1String("\',");
writeLineEnd();
m_printed += QLatin1String("from: {");
m_printed += QString::number(start.line());
m_printed += QLatin1String(", ");
m_printed += QString::number(start.column());
m_printed += QLatin1String("},");
m_printed += QLatin1String("to: {");
m_printed += QString::number(end.line());
m_printed += QLatin1String(", ");
m_printed += QString::number(end.column());
m_printed += QLatin1Char('}');
m_indent -= 4;
writeLineEnd();
m_printed += QLatin1Char('}');
}
void CXPrettyPrinter::writeLocationJson(const CXSourceLocation &location)
{
SourceLocation loc = getSpellingLocation(location);
m_printed += QLatin1Char('{');
m_indent += 4;
writeLineEnd();
m_printed += QLatin1String("file: \'");
m_printed += loc.fileName();
m_printed += QLatin1String("\',");
writeLineEnd();
m_printed += QLatin1String("line: ");
m_printed += QString::number(loc.line());
m_printed += QLatin1String(",");
writeLineEnd();
m_printed += QLatin1String("column: ");
m_printed += QString::number(loc.column());
m_indent -= 4;
writeLineEnd();
m_printed += QLatin1String("}");
}
void CXPrettyPrinter::writeLineEnd()
{
m_printed += QLatin1Char('\n');
for (int i = 0; i < m_indent; ++i)
m_printed += QLatin1Char(' ');
}

View File

@@ -0,0 +1,75 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef CXPRETTYPRINTER_H
#define CXPRETTYPRINTER_H
#include <clang-c/Index.h>
#include <QString>
namespace ClangCodeModel {
namespace Internal {
class CXPrettyPrinter
{
public:
CXPrettyPrinter();
QString toString(CXCompletionChunkKind kind) const;
QString toString(CXAvailabilityKind kind) const;
QString toString(CXCursorKind kind) const;
QString toString(CXDiagnosticSeverity severity) const;
QString jsonForCompletionMeta(CXCodeCompleteResults *results);
QString jsonForCompletionString(const CXCompletionString &string);
QString jsonForCompletion(const CXCompletionResult &result);
QString jsonForDiagnsotic(const CXDiagnostic &diagnostic);
private:
int m_indent;
QString m_printed;
void writeCompletionContexts(CXCodeCompleteResults *results);
void writeCompletionStringJson(const CXCompletionString &string);
void writeCompletionChunkJson(const CXCompletionString &string, unsigned i);
void writeCompletionAnnotationJson(const CXCompletionString &string, unsigned i);
void writeDiagnosticJson(const CXDiagnostic &diag);
void writeFixItJson(const CXDiagnostic &diag, unsigned i);
void writeRangeJson(const CXSourceRange &range);
void writeLocationJson(const CXSourceLocation &location);
void writeLineEnd();
};
} // namespace Internal
} // namespace ClangCodeModel
#endif // CXPRETTYPRINTER_H

View File

@@ -0,0 +1,145 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef CXRAII_H
#define CXRAII_H
#include <clang-c/Index.h>
// Simple RAII types for their CX correspondings
namespace ClangCodeModel {
namespace Internal {
template <class CXType_T>
struct ScopedCXType
{
protected:
typedef void (*DisposeFunction)(CXType_T);
ScopedCXType(DisposeFunction f)
: m_cx(0), m_disposeFunction(f)
{}
ScopedCXType(const CXType_T &cx, DisposeFunction f)
: m_cx(cx) , m_disposeFunction(f)
{}
public:
~ScopedCXType()
{
dispose();
}
operator CXType_T() const { return m_cx; }
bool operator!() const { return !m_cx; }
bool isNull() const { return !m_cx; }
void reset(const CXType_T &cx)
{
dispose();
m_cx = cx;
}
private:
ScopedCXType(const ScopedCXType &);
const ScopedCXType &operator=(const ScopedCXType &);
void dispose()
{
if (m_cx)
m_disposeFunction(m_cx);
}
CXType_T m_cx;
DisposeFunction m_disposeFunction;
};
struct ScopedCXIndex : ScopedCXType<CXIndex>
{
ScopedCXIndex()
: ScopedCXType<CXIndex>(&clang_disposeIndex)
{}
ScopedCXIndex(const CXIndex &index)
: ScopedCXType<CXIndex>(index, &clang_disposeIndex)
{}
};
struct ScopedCXTranslationUnit : ScopedCXType<CXTranslationUnit>
{
ScopedCXTranslationUnit()
: ScopedCXType<CXTranslationUnit>(&clang_disposeTranslationUnit)
{}
ScopedCXTranslationUnit(const CXTranslationUnit &unit)
: ScopedCXType<CXTranslationUnit>(unit, &clang_disposeTranslationUnit)
{}
};
struct ScopedCXDiagnostic : ScopedCXType<CXDiagnostic>
{
ScopedCXDiagnostic()
: ScopedCXType<CXDiagnostic>(&clang_disposeDiagnostic)
{}
ScopedCXDiagnostic(const CXDiagnostic &diagnostic)
: ScopedCXType<CXDiagnostic>(diagnostic, &clang_disposeDiagnostic)
{}
};
struct ScopedCXDiagnosticSet : ScopedCXType<CXDiagnostic>
{
ScopedCXDiagnosticSet()
: ScopedCXType<CXDiagnosticSet>(&clang_disposeDiagnosticSet)
{}
ScopedCXDiagnosticSet(const CXDiagnostic &diagnostic)
: ScopedCXType<CXDiagnosticSet>(diagnostic, &clang_disposeDiagnosticSet)
{}
};
struct ScopedCXCodeCompleteResults : ScopedCXType<CXCodeCompleteResults*>
{
ScopedCXCodeCompleteResults()
: ScopedCXType<CXCodeCompleteResults*>(&clang_disposeCodeCompleteResults)
{}
ScopedCXCodeCompleteResults(CXCodeCompleteResults *results)
: ScopedCXType<CXCodeCompleteResults*>(results, &clang_disposeCodeCompleteResults)
{}
unsigned size() const
{
return static_cast<CXCodeCompleteResults *>(*this)->NumResults;
}
const CXCompletionResult &completionAt(unsigned i)
{
return static_cast<CXCodeCompleteResults *>(*this)->Results[i];
}
};
} // Internal
} // ClangCodeModel
#endif // CXRAII_H

View File

@@ -0,0 +1,208 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "dependencygraph.h"
#include <QtCore/QtConcurrentRun>
using namespace ClangCodeModel;
using namespace Internal;
DependencyGraph::DependencyGraph()
{
m_includeTracker.setResolutionMode(IncludeTracker::EveryMatchResolution);
}
DependencyGraph::~DependencyGraph()
{
discard();
}
void DependencyGraph::cancel()
{
if (m_computeWatcher.isRunning()) {
m_computeWatcher.cancel();
m_computeWatcher.waitForFinished();
}
}
void DependencyGraph::addFile(const QString &fileName, const QStringList &compilationOptions)
{
cancel();
m_files.append(qMakePair(fileName, compilationOptions));
}
QFuture<void> DependencyGraph::compute()
{
QFuture<void> future = QtConcurrent::run(this, &DependencyGraph::computeCore);
m_computeWatcher.setFuture(future);
return future;
}
void DependencyGraph::computeCore()
{
for (int i = 0; i < m_files.size(); ++i) {
if (m_computeWatcher.isCanceled())
break;
const QPair<QString, QStringList> &p = m_files.at(i);
const QString &currentFile = p.first;
const QStringList &options = p.second;
const QPair<bool, NodeRefSetIt> &v = findVertex(currentFile);
if (!v.first)
processIncludes(insertVertex(currentFile), options);
}
emit dependencyGraphAvailable();
}
void DependencyGraph::processIncludes(NodeRefSetIt currentIt,
const QStringList &compilationOptions)
{
const QString &currentFile = currentIt.key();
const QStringList &includes = m_includeTracker.directIncludes(currentFile, compilationOptions);
foreach (const QString &include, includes) {
if (m_computeWatcher.isCanceled())
return;
QPair<bool, NodeRefSetIt> v = findVertex(include);
if (!v.first) {
v.second = insertVertex(include);
processIncludes(v.second, compilationOptions);
}
insertEdge(currentIt, v.second);
}
}
namespace {
struct SimpleVisitor
{
bool acceptFile(const QString &fileName)
{
m_allFiles.append(fileName);
return false;
}
QStringList m_allFiles;
};
}
QStringList DependencyGraph::collectDependencies(const QString &referenceFile,
DependencyRole role) const
{
SimpleVisitor visitor;
collectDependencies(referenceFile, role, &visitor);
return visitor.m_allFiles;
}
bool DependencyGraph::hasDependency(const QString &referenceFile, DependencyRole role) const
{
QPair<bool, NodeRefSetIt> v = findVertex(referenceFile);
if (!v.first)
return false;
NodeListIt nodeIt = v.second.value();
if (role == FilesDirectlyIncludedBy || role == FilesIncludedBy)
return nodeIt->m_out != 0;
return nodeIt->m_in != 0;
}
void DependencyGraph::discard()
{
cancel();
for (NodeListIt it = m_nodes.begin(); it != m_nodes.end(); ++it) {
deleteAdjacencies(it->m_out);
deleteAdjacencies(it->m_in);
}
m_nodes.clear();
m_nodesRefs.clear();
m_files.clear();
}
DependencyGraph::Node::Node(const QString &fileName)
: m_fileName(fileName)
, m_out(0)
, m_in(0)
{}
DependencyGraph::AdjacencyNode::AdjacencyNode(NodeListIt it)
: m_next(0)
, m_nodeIt(it)
{}
QPair<bool, DependencyGraph::NodeRefSetIt> DependencyGraph::findVertex(const QString &s) const
{
bool found = false;
NodeRefSetIt it = const_cast<NodeRefSet &>(m_nodesRefs).find(s);
if (it != m_nodesRefs.end())
found = true;
return qMakePair(found, it);
}
DependencyGraph::NodeRefSetIt DependencyGraph::insertVertex(const QString &s)
{
Q_ASSERT(m_nodesRefs.find(s) == m_nodesRefs.end());
m_nodes.append(Node(s));
return m_nodesRefs.insert(s, m_nodes.end() - 1);
}
void DependencyGraph::insertEdge(DependencyGraph::NodeRefSetIt fromIt,
DependencyGraph::NodeRefSetIt toIt)
{
NodeListIt nodeFromIt = fromIt.value();
NodeListIt nodeToIt = toIt.value();
createAdjacency(&nodeFromIt->m_out, new AdjacencyNode(nodeToIt));
createAdjacency(&nodeToIt->m_in, new AdjacencyNode(nodeFromIt));
}
void DependencyGraph::deleteAdjacencies(AdjacencyNode *node)
{
while (node) {
AdjacencyNode *next = node->m_next;
delete node;
node = next;
}
}
void DependencyGraph::createAdjacency(AdjacencyNode **node, AdjacencyNode *newNode)
{
if (*node)
newNode->m_next = *node;
*node = newNode;
}

View File

@@ -0,0 +1,235 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef DEPENDENCYGRAPH_H
#define DEPENDENCYGRAPH_H
#include "includetracker.h"
#include <QtCore/QObject>
#include <QtCore/QStringList>
#include <QtCore/QLinkedList>
#include <QtCore/QHash>
#include <QtCore/QPair>
#include <QtCore/QQueue>
#include <QtCore/QFuture>
#include <QtCore/QFutureWatcher>
#include <QtCore/QDebug>
namespace ClangCodeModel {
namespace Internal {
class DependencyGraph : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(DependencyGraph)
public:
DependencyGraph();
~DependencyGraph();
void addFile(const QString &fileName, const QStringList &compilationOptions);
QFuture<void> compute();
enum DependencyRole
{
FilesDirectlyIncludedBy, // Only direct inclusions
FilesIncludedBy, // Both direct and indirect inclusions
FilesWhichDirectlyInclude, // This one is directly included from...
FilesWhichInclude // This one is directly or indirectly included from...
};
/*
* You should use this version if you simply want all the dependencies, no matter what.
*/
QStringList collectDependencies(const QString &referenceFile, DependencyRole role) const;
/*
* You should use this version if you might be interested on a particular dependency
* and don't want to continue the search once you have found it. In this case you need
* supply a visitor. Currently the visitor concept simply requires that a type Visitor_T
* models a function that will receive a file string s and indicate whether or not to
* continue:
*
* Visitor_T().acceptFile(s) must be a valid expression.
*
*/
template <class Visitor_T>
void collectDependencies(const QString &referenceFile,
DependencyRole role,
Visitor_T *visitor) const;
bool hasDependency(const QString &referenceFile, DependencyRole role) const;
void discard();
signals:
void dependencyGraphAvailable();
private:
QList<QPair<QString, QStringList> > m_files;
IncludeTracker m_includeTracker;
QFutureWatcher<void> m_computeWatcher;
void cancel();
void computeCore();
// The dependency graph is represent as an adjacency list. The vertices contains
// a list of *out* edges and a list of *in* edges. Each vertex corresponds to a file.
// Its out edges correspond to the files which get directly included by this one, while
// its in edges correspond to files that directly include this one.
//
// For better space efficiency, the adjacency nodes doen't explicitly store the file
// names themselves, but rather an iterator to the corresponding vertex. In addition,
// for speed efficiency we keep track of a hash table that contains iterators to the
// actual vertex storage container, which actually contains the strings for the file
// names. The vertex container itself is a linked list, it has the semantics we need,
// in particular regarding iterator invalidation.
struct AdjacencyNode;
struct Node
{
Node(const QString &fileName);
QString m_fileName;
AdjacencyNode *m_out;
AdjacencyNode *m_in;
};
typedef QLinkedList<Node> NodeList;
typedef NodeList::iterator NodeListIt;
typedef QHash<QString, NodeListIt> NodeRefSet;
typedef NodeRefSet::iterator NodeRefSetIt;
struct AdjacencyNode
{
AdjacencyNode(NodeListIt it);
AdjacencyNode *m_next;
NodeListIt m_nodeIt;
};
void processIncludes(NodeRefSetIt currentFileIt,
const QStringList &compilationOptions);
template <class Visitor_T>
void collectFilesBFS(NodeListIt nodeIt, DependencyRole role, Visitor_T *visitor) const;
// Core graph operations and data
QPair<bool, NodeRefSetIt> findVertex(const QString &s) const;
NodeRefSetIt insertVertex(const QString &s);
void insertEdge(NodeRefSetIt fromIt, NodeRefSetIt toIt);
void deleteAdjacencies(AdjacencyNode *node);
void createAdjacency(AdjacencyNode **node, AdjacencyNode *newNode);
NodeList m_nodes;
NodeRefSet m_nodesRefs;
};
template <class Visitor_T>
void DependencyGraph::collectDependencies(const QString &referenceFile,
DependencyRole role,
Visitor_T *visitor) const
{
if (m_computeWatcher.isRunning())
return;
QPair<bool, NodeRefSetIt> v = findVertex(referenceFile);
if (!v.first)
return;
NodeListIt nodeIt = v.second.value();
if (role == FilesDirectlyIncludedBy || role == FilesWhichDirectlyInclude) {
AdjacencyNode *adj;
if (role == FilesDirectlyIncludedBy)
adj = nodeIt->m_out;
else
adj = nodeIt->m_in;
for (; adj; adj = adj->m_next) {
NodeListIt dependentIt = adj->m_nodeIt;
if (visitor->acceptFile(dependentIt->m_fileName))
return;
}
} else {
collectFilesBFS(nodeIt, role, visitor);
}
}
template <class Visitor_T>
void DependencyGraph::collectFilesBFS(NodeListIt nodeIt,
DependencyRole role,
Visitor_T *visitor) const
{
Q_ASSERT(role == FilesIncludedBy || role == FilesWhichInclude);
if (m_computeWatcher.isRunning())
return;
QQueue<NodeListIt> q;
q.enqueue(nodeIt);
QSet<QString> visited;
visited.insert(nodeIt->m_fileName);
while (!q.isEmpty()) {
NodeListIt currentIt = q.dequeue();
AdjacencyNode *adj;
if (role == FilesIncludedBy)
adj = currentIt->m_out;
else
adj = currentIt->m_in;
while (adj) {
NodeListIt adjNodeIt = adj->m_nodeIt;
adj = adj->m_next;
const QString &adjFileName = adjNodeIt->m_fileName;
if (visited.contains(adjFileName))
continue;
if (visitor->acceptFile(adjFileName))
return;
visited.insert(adjFileName);
q.enqueue(adjNodeIt);
}
}
}
} // Internal
} // ClangCodeModel
#endif // DEPENDENCYGRAPH_H

View File

@@ -0,0 +1,63 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "diagnostic.h"
#include <QtCore/QCoreApplication>
#include <QtCore/QStringList>
using namespace ClangCodeModel;
Diagnostic::Diagnostic()
: m_severity(Unknown)
, m_length(0)
{}
Diagnostic::Diagnostic(Severity severity, const SourceLocation &location, unsigned length, const QString &spelling)
: m_severity(severity)
, m_loc(location)
, m_length(length)
, m_spelling(spelling)
{}
const QString Diagnostic::severityAsString() const
{
if (m_severity == Unknown)
return QString();
static QStringList strs = QStringList()
<< QCoreApplication::translate("Diagnostic", "ignored")
<< QCoreApplication::translate("Diagnostic", "note")
<< QCoreApplication::translate("Diagnostic", "warning")
<< QCoreApplication::translate("Diagnostic", "error")
<< QCoreApplication::translate("Diagnostic", "fatal")
;
return strs.at(m_severity);
}

View File

@@ -0,0 +1,82 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef CLANG_DIAGNOSTIC_H
#define CLANG_DIAGNOSTIC_H
#include "clang_global.h"
#include "sourcelocation.h"
#include <QMetaType>
namespace ClangCodeModel {
class CLANG_EXPORT Diagnostic
{
public:
enum Severity {
Unknown = -1,
Ignored = 0,
Note = 1,
Warning = 2,
Error = 3,
Fatal = 4
};
public:
Diagnostic();
Diagnostic(Severity severity, const SourceLocation &location, unsigned length, const QString &spelling);
Severity severity() const
{ return m_severity; }
const QString severityAsString() const;
const SourceLocation &location() const
{ return m_loc; }
unsigned length() const
{ return m_length; }
const QString &spelling() const
{ return m_spelling; }
private:
Severity m_severity;
SourceLocation m_loc;
unsigned m_length;
QString m_spelling;
};
} // namespace ClangCodeModel
Q_DECLARE_METATYPE(ClangCodeModel::Diagnostic)
Q_DECLARE_METATYPE(QList<ClangCodeModel::Diagnostic>)
#endif // CLANG_DIAGNOSTIC_H

View File

@@ -0,0 +1,36 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "fastindexer.h"
using namespace ClangCodeModel::Internal;
FastIndexer::~FastIndexer()
{
}

View File

@@ -0,0 +1,49 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef FASTINDEXER_H
#define FASTINDEXER_H
#include "unit.h"
namespace ClangCodeModel {
namespace Internal {
class FastIndexer
{
public:
virtual ~FastIndexer() = 0;
virtual void indexNow(const Unit &unit) = 0;
};
} // Internal namespace
} // ClangCodeModel namespace
#endif // FASTINDEXER_H

View File

@@ -0,0 +1,491 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "clangsymbolsearcher.h"
#include "index.h"
#include <QStringList>
#include <QLinkedList>
#include <QHash>
#include <QDataStream>
#include <QPair>
#include <QFileInfo>
#include <QMutex>
#include <QMutexLocker>
namespace ClangCodeModel {
namespace Internal {
class ClangSymbolSearcher;
class IndexPrivate
{
public:
IndexPrivate();
void insertSymbol(const Symbol &symbol, const QDateTime &timeStamp);
QList<Symbol> symbols(const QString &fileName) const;
QList<Symbol> symbols(const QString &fileName, Symbol::Kind kind) const;
QList<Symbol> symbols(const QString &fileName, Symbol::Kind kind, const QString &uqName) const;
QList<Symbol> symbols(const QString &fileName, const QString &uqName) const;
QList<Symbol> symbols(Symbol::Kind kind) const;
void match(ClangSymbolSearcher *searcher) const;
void insertFile(const QString &fileName, const QDateTime &timeStamp);
void removeFile(const QString &fileName);
void removeFiles(const QStringList &fileNames);
bool containsFile(const QString &fileName) const;
QStringList files() const;
void clear();
bool isEmpty() const;
void trackTimeStamp(const Symbol &symbol, const QDateTime &timeStamp);
void trackTimeStamp(const QString &fileName, const QDateTime &timeStamp);
bool validate(const QString &fileName) const;
QByteArray serialize() const;
void deserialize(const QByteArray &data);
private:
typedef QLinkedList<Symbol> SymbolCont;
typedef SymbolCont::iterator SymbolIt;
typedef QHash<QString, QList<SymbolIt> > NameIndex;
typedef QHash<Symbol::Kind, NameIndex> KindIndex;
typedef QHash<QString, KindIndex> FileIndex;
typedef QList<SymbolIt>::iterator SymbolIndexIt;
typedef NameIndex::iterator NameIndexIt;
typedef KindIndex::iterator KindIndexIt;
typedef FileIndex::iterator FileIndexIt;
typedef FileIndex::const_iterator FileIndexCIt;
void insertSymbol(const Symbol &symbol);
void removeSymbol(SymbolIndexIt it);
QPair<bool, SymbolIndexIt> findEquivalentSymbol(const Symbol &symbol);
void updateEquivalentSymbol(SymbolIndexIt it, const Symbol &symbol);
void createIndexes(SymbolIt it);
QList<SymbolIt> removeIndexes(const QString &fileName);
static QList<Symbol> symbolsFromIterators(const QList<SymbolIt> &symbolList);
// @TODO: Sharing of compilation options...
mutable QMutex m_mutex;
SymbolCont m_container;
FileIndex m_files;
QHash<QString, QDateTime> m_timeStamps;
};
} // namespace Internal
} // namespace ClangCodeModel
using namespace ClangCodeModel;
using namespace Internal;
IndexPrivate::IndexPrivate()
: m_mutex(QMutex::Recursive)
{
}
void IndexPrivate::createIndexes(SymbolIt it)
{
m_files[it->m_location.fileName()][it->m_kind][it->m_name].append(it);
}
QList<QLinkedList<Symbol>::iterator> IndexPrivate::removeIndexes(const QString &fileName)
{
QList<SymbolIt> iterators;
KindIndex kindIndex = m_files.take(fileName);
KindIndexIt it = kindIndex.begin();
KindIndexIt eit = kindIndex.end();
for (; it != eit; ++it) {
NameIndex nameIndex = *it;
NameIndexIt nit = nameIndex.begin();
NameIndexIt neit = nameIndex.end();
for (; nit != neit; ++nit)
iterators.append(*nit);
}
return iterators;
}
void IndexPrivate::insertSymbol(const Symbol &symbol)
{
QMutexLocker locker(&m_mutex);
SymbolIt it = m_container.insert(m_container.begin(), symbol);
createIndexes(it);
}
void IndexPrivate::insertSymbol(const Symbol &symbol, const QDateTime &timeStamp)
{
const QPair<bool, SymbolIndexIt> &find = findEquivalentSymbol(symbol);
if (find.first)
updateEquivalentSymbol(find.second, symbol);
else
insertSymbol(symbol);
trackTimeStamp(symbol, timeStamp);
}
QPair<bool, IndexPrivate::SymbolIndexIt> IndexPrivate::findEquivalentSymbol(const Symbol &symbol)
{
// Despite the loop below finding a symbol should be efficient, since we already filter
// the file name, the kind, and the qualified name through the indexing mechanism. In many
// cases it will iterate only once.
QList<SymbolIt> &byName = m_files[symbol.m_location.fileName()][symbol.m_kind][symbol.m_name];
for (SymbolIndexIt it = byName.begin(); it != byName.end(); ++it) {
const Symbol &candidateSymbol = *(*it);
// @TODO: Overloads, template specializations
if (candidateSymbol.m_qualification == symbol.m_qualification)
return qMakePair(true, it);
}
return qMakePair(false, QList<SymbolIt>::iterator());
}
void IndexPrivate::updateEquivalentSymbol(SymbolIndexIt it, const Symbol &symbol)
{
SymbolIt symbolIt = *it;
Q_ASSERT(symbolIt->m_kind == symbol.m_kind);
Q_ASSERT(symbolIt->m_qualification == symbol.m_qualification);
Q_ASSERT(symbolIt->m_name == symbol.m_name);
Q_ASSERT(symbolIt->m_location.fileName() == symbol.m_location.fileName());
symbolIt->m_location = symbol.m_location;
}
void IndexPrivate::removeSymbol(SymbolIndexIt it)
{
SymbolIt symbolIt = *it;
m_container.erase(symbolIt);
KindIndex &kindIndex = m_files[symbolIt->m_location.fileName()];
NameIndex &nameIndex = kindIndex[symbolIt->m_kind];
QList<SymbolIt> &byName = nameIndex[symbolIt->m_name];
byName.erase(it);
if (byName.isEmpty()) {
nameIndex.remove(symbolIt->m_name);
if (nameIndex.isEmpty()) {
kindIndex.remove(symbolIt->m_kind);
if (kindIndex.isEmpty())
m_files.remove(symbolIt->m_location.fileName());
}
}
}
QList<Symbol> IndexPrivate::symbols(const QString &fileName) const
{
QMutexLocker locker(&m_mutex);
QList<Symbol> all;
const QList<NameIndex> &byKind = m_files.value(fileName).values();
foreach (const NameIndex &nameIndex, byKind) {
const QList<QList<SymbolIt> > &byName = nameIndex.values();
foreach (const QList<SymbolIt> &symbols, byName)
all.append(symbolsFromIterators(symbols));
}
return all;
}
QList<Symbol> IndexPrivate::symbols(const QString &fileName, Symbol::Kind kind) const
{
QMutexLocker locker(&m_mutex);
QList<Symbol> all;
const QList<QList<SymbolIt> > &byName = m_files.value(fileName).value(kind).values();
foreach (const QList<SymbolIt> &symbols, byName)
all.append(symbolsFromIterators(symbols));
return all;
}
QList<Symbol> IndexPrivate::symbols(const QString &fileName,
Symbol::Kind kind,
const QString &uqName) const
{
QMutexLocker locker(&m_mutex);
return symbolsFromIterators(m_files.value(fileName).value(kind).value(uqName));
}
QList<Symbol> IndexPrivate::symbols(Symbol::Kind kind) const
{
QMutexLocker locker(&m_mutex);
QList<Symbol> all;
FileIndexCIt it = m_files.begin();
FileIndexCIt eit = m_files.end();
for (; it != eit; ++it)
all.append(symbols(it.key(), kind));
return all;
}
void IndexPrivate::match(ClangSymbolSearcher *searcher) const
{
QMutexLocker locker(&m_mutex);
searcher->search(m_container);
}
QList<Symbol> IndexPrivate::symbolsFromIterators(const QList<SymbolIt> &symbolList)
{
QList<Symbol> all;
foreach (SymbolIt symbolIt, symbolList)
all.append(*symbolIt);
return all;
}
void IndexPrivate::trackTimeStamp(const Symbol &symbol, const QDateTime &timeStamp)
{
QMutexLocker locker(&m_mutex);
trackTimeStamp(symbol.m_location.fileName(), timeStamp);
}
void IndexPrivate::trackTimeStamp(const QString &fileName, const QDateTime &timeStamp)
{
QMutexLocker locker(&m_mutex);
// We keep track of time stamps on a per file basis (most recent one).
m_timeStamps[fileName] = timeStamp;
}
bool IndexPrivate::validate(const QString &fileName) const
{
QMutexLocker locker(&m_mutex);
const QDateTime &timeStamp = m_timeStamps.value(fileName);
if (!timeStamp.isValid())
return false;
QFileInfo fileInfo(fileName);
if (fileInfo.lastModified() > timeStamp)
return false;
return true;
}
void IndexPrivate::insertFile(const QString &fileName, const QDateTime &timeStamp)
{
QMutexLocker locker(&m_mutex);
trackTimeStamp(fileName, timeStamp);
}
QStringList IndexPrivate::files() const
{
QMutexLocker locker(&m_mutex);
return m_timeStamps.keys();
}
bool IndexPrivate::containsFile(const QString &fileName) const
{
QMutexLocker locker(&m_mutex);
return m_timeStamps.contains(fileName);
}
void IndexPrivate::removeFile(const QString &fileName)
{
QMutexLocker locker(&m_mutex);
const QList<SymbolIt> &iterators = removeIndexes(fileName);
foreach (SymbolIt it, iterators)
m_container.erase(it);
m_timeStamps.remove(fileName);
}
void IndexPrivate::removeFiles(const QStringList &fileNames)
{
QMutexLocker locker(&m_mutex);
foreach (const QString &fileName, fileNames)
removeFile(fileName);
}
void IndexPrivate::clear()
{
QMutexLocker locker(&m_mutex);
m_container.clear();
m_files.clear();
m_timeStamps.clear();
}
bool IndexPrivate::isEmpty() const
{
QMutexLocker locker(&m_mutex);
return m_timeStamps.isEmpty();
}
QByteArray IndexPrivate::serialize() const
{
QMutexLocker locker(&m_mutex);
QByteArray data;
QDataStream stream(&data, QIODevice::WriteOnly);
stream << (quint32)0x0A0BFFEE;
stream << (quint16)1;
stream.setVersion(QDataStream::Qt_4_7);
stream << m_container;
stream << m_timeStamps;
return data;
}
void IndexPrivate::deserialize(const QByteArray &data)
{
QMutexLocker locker(&m_mutex);
clear();
// @TODO: Version compatibility handling.
QDataStream stream(data);
quint32 header;
stream >> header;
if (header != 0x0A0BFFEE)
return;
quint16 indexVersion;
stream >> indexVersion;
if (indexVersion != 1)
return;
stream.setVersion(QDataStream::Qt_4_7);
SymbolCont symbols;
stream >> symbols;
stream >> m_timeStamps;
// @TODO: Overload the related functions with batch versions.
foreach (const Symbol &symbol, symbols)
insertSymbol(symbol);
}
Index::Index()
: d(new IndexPrivate)
{}
Index::~Index()
{}
void Index::insertSymbol(const Symbol &symbol, const QDateTime &timeStamp)
{
d->insertSymbol(symbol, timeStamp);
}
QList<Symbol> Index::symbols(const QString &fileName) const
{
return d->symbols(fileName);
}
QList<Symbol> Index::symbols(const QString &fileName, Symbol::Kind kind) const
{
return d->symbols(fileName, kind);
}
QList<Symbol> Index::symbols(const QString &fileName, Symbol::Kind kind, const QString &uqName) const
{
return d->symbols(fileName, kind, uqName);
}
QList<Symbol> Index::symbols(Symbol::Kind kind) const
{
return d->symbols(kind);
}
void Index::match(ClangSymbolSearcher *searcher) const
{
d->match(searcher);
}
void Index::insertFile(const QString &fileName, const QDateTime &timeStamp)
{
d->insertFile(fileName, timeStamp);
}
QStringList Index::files() const
{
return d->files();
}
bool Index::containsFile(const QString &fileName) const
{
return d->containsFile(fileName);
}
void Index::removeFile(const QString &fileName)
{
d->removeFile(fileName);
}
void Index::removeFiles(const QStringList &fileNames)
{
d->removeFiles(fileNames);
}
void Index::clear()
{
d->clear();
}
bool Index::isEmpty() const
{
return d->isEmpty();
}
bool Index::validate(const QString &fileName) const
{
return d->validate(fileName);
}
QByteArray Index::serialize() const
{
return d->serialize();
}
void Index::deserialize(const QByteArray &data)
{
d->deserialize(data);
}

View File

@@ -0,0 +1,87 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef INDEX_H
#define INDEX_H
#include "symbol.h"
#include <QtCore/QByteArray>
#include <QtCore/QString>
#include <QtCore/QList>
#include <QtCore/QScopedPointer>
#include <QtCore/QDateTime>
#include <QStringList>
namespace ClangCodeModel {
class Symbol;
namespace Internal {
class ClangSymbolSearcher;
class IndexPrivate;
class Index
{
public:
Index();
~Index();
void insertSymbol(const Symbol &symbol, const QDateTime &timeStamp);
QList<Symbol> symbols(const QString &fileName) const;
QList<Symbol> symbols(const QString &fileName, Symbol::Kind kind) const;
QList<Symbol> symbols(const QString &fileName, Symbol::Kind kind, const QString &uqName) const;
QList<Symbol> symbols(Symbol::Kind kind) const;
void match(ClangSymbolSearcher *searcher) const;
void insertFile(const QString &fileName, const QDateTime &timeStamp);
void removeFile(const QString &fileName);
void removeFiles(const QStringList &fileNames);
bool containsFile(const QString &fileName) const;
QStringList files() const;
bool validate(const QString &fileName) const;
void clear();
bool isEmpty() const;
QByteArray serialize() const;
void deserialize(const QByteArray &data);
private:
QScopedPointer<IndexPrivate> d;
};
} // Internal
} // ClangCodeModel
#endif // INDEX_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,103 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef INDEXER_H
#define INDEXER_H
#include "clang_global.h"
#include "symbol.h"
#include "unit.h"
#include <cpptools/cppmodelmanagerinterface.h>
#include <QtCore/QObject>
#include <QtCore/QString>
#include <QtCore/QStringList>
#include <QtCore/QScopedPointer>
#include <QtCore/QFuture>
namespace ClangCodeModel {
namespace Internal {
class ClangSymbolSearcher;
} // namespace Internal
class IndexerPrivate;
class CLANG_EXPORT Indexer : public QObject
{
Q_OBJECT
public:
typedef CppTools::ProjectPart ProjectPart;
public:
Indexer(QObject *parent = 0);
~Indexer();
void initialize(const QString &storagePath);
void finalize();
void regenerate();
void evaluateFile(const QString &fileName);
bool isBusy() const;
void cancel(bool waitForFinished);
bool addFile(const QString &fileName, ProjectPart::Ptr projectPart);
QStringList allFiles() const;
QStringList compilationOptions(const QString &fileName) const;
QList<Symbol> allFunctions() const;
QList<Symbol> allClasses() const;
QList<Symbol> allMethods() const;
QList<Symbol> allConstructors() const;
QList<Symbol> allDestructors() const;
QList<Symbol> functionsFromFile(const QString &fileName) const;
QList<Symbol> classesFromFile(const QString &fileName) const;
QList<Symbol> methodsFromFile(const QString &fileName) const;
QList<Symbol> constructorsFromFile(const QString &fileName) const;
QList<Symbol> destructorsFromFile(const QString &fileName) const;
QList<Symbol> allFromFile(const QString &fileName) const;
void match(Internal::ClangSymbolSearcher *searcher) const;
void runQuickIndexing(const Internal::Unit &unit, const ProjectPart::Ptr &part);
signals:
void indexingStarted(QFuture<void> future);
void indexingFinished();
private:
friend class IndexerPrivate;
QScopedPointer<IndexerPrivate> m_d;
};
} // ClangCodeModel
#endif // INDEXER_H

View File

@@ -0,0 +1,91 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "liveunitsmanager.h"
#include <coreplugin/idocument.h>
using namespace ClangCodeModel;
using namespace Internal;
LiveUnitsManager *LiveUnitsManager::m_instance = 0;
LiveUnitsManager::LiveUnitsManager()
{
Q_ASSERT(!m_instance);
m_instance = this;
qRegisterMetaType<ClangCodeModel::Internal::Unit>();
}
LiveUnitsManager::~LiveUnitsManager()
{
m_instance = 0;
}
void LiveUnitsManager::requestTracking(const QString &fileName)
{
if (!fileName.isEmpty() && !isTracking(fileName))
m_units.insert(fileName, Unit(fileName));
}
void LiveUnitsManager::cancelTrackingRequest(const QString &fileName)
{
if (!isTracking(fileName))
return;
// If no one else is tracking this particular unit, we remove it.
if (m_units[fileName].isUnique())
m_units.remove(fileName);
}
void LiveUnitsManager::updateUnit(const QString &fileName, const Unit &unit)
{
if (!isTracking(fileName))
return;
m_units[fileName] = unit;
emit unitAvailable(unit);
}
Unit LiveUnitsManager::unit(const QString &fileName)
{
return m_units.value(fileName);
}
void LiveUnitsManager::editorOpened(Core::IEditor *editor)
{
requestTracking(editor->document()->filePath());
}
void LiveUnitsManager::editorAboutToClose(Core::IEditor *editor)
{
cancelTrackingRequest(editor->document()->filePath());
}

View File

@@ -0,0 +1,78 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef LIVEUNITSMANAGER_H
#define LIVEUNITSMANAGER_H
#include "unit.h"
#include <coreplugin/editormanager/ieditor.h>
#include <QtCore/QObject>
#include <QtCore/QString>
#include <QtCore/QHash>
namespace ClangCodeModel {
namespace Internal {
class LiveUnitsManager : public QObject
{
Q_OBJECT
public:
LiveUnitsManager();
~LiveUnitsManager();
static LiveUnitsManager *instance()
{ return m_instance; }
void requestTracking(const QString &fileName);
bool isTracking(const QString &fileName) const
{ return m_units.contains(fileName); }
void cancelTrackingRequest(const QString &fileName);
void updateUnit(const QString &fileName, const Unit &unit);
Unit unit(const QString &fileName);
public slots:
void editorOpened(Core::IEditor *editor);
void editorAboutToClose(Core::IEditor *editor);
signals:
void unitAvailable(const ClangCodeModel::Internal::Unit &unit);
private:
static LiveUnitsManager *m_instance;
QHash<QString, Unit> m_units;
};
} // Internal
} // ClangCodeModel
#endif // LIVEUNITSMANAGER_H

View File

@@ -0,0 +1,62 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "pchinfo.h"
#include <QDir>
using namespace ClangCodeModel::Internal;
PchInfo::PchInfo()
{
}
PchInfo::~PchInfo()
{
}
PchInfo::Ptr PchInfo::createEmpty()
{
return Ptr(new PchInfo);
}
PchInfo::Ptr PchInfo::createWithFileName(const QString &inputFileName,
const QStringList &options,
bool objcEnabled)
{
Ptr result(new PchInfo);
result->m_inputFileName = inputFileName;
result->m_options = options;
result->m_objcEnabled = objcEnabled;
// The next 2 lines are just here to generate the file name....
result->m_file.open();
result->m_file.close();
return result;
}

View File

@@ -0,0 +1,80 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef PCHINFO_H
#define PCHINFO_H
#include <QString>
#include <QStringList>
#include <QSharedPointer>
#include <QTemporaryFile>
namespace ClangCodeModel {
namespace Internal {
class PchInfo
{
PchInfo();
public:
typedef QSharedPointer<PchInfo> Ptr;
public:
~PchInfo();
static Ptr createEmpty();
static Ptr createWithFileName(const QString &inputFileName,
const QStringList &options, bool objcEnabled);
/// \return the (temporary) file name for the PCH file.
QString fileName() const
{ return m_file.fileName(); }
/// \return the input file for the PCH compilation.
QString inputFileName() const
{ return m_inputFileName; }
/// \return the options used to generate this PCH file.
QStringList options() const
{ return m_options; }
bool objcWasEnabled() const
{ return m_objcEnabled; }
private:
QString m_inputFileName;
QStringList m_options;
bool m_objcEnabled;
QTemporaryFile m_file;
};
} // Internal namespace
} // ClangCodeModel namespace
#endif // PCHINFO_H

View File

@@ -0,0 +1,433 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "pchmanager.h"
#include "utils.h"
#include "clangutils.h"
#include <coreplugin/icore.h>
#include <coreplugin/progressmanager/progressmanager.h>
#include <utils/runextensions.h>
#include <QFile>
using namespace ClangCodeModel;
using namespace ClangCodeModel::Internal;
using namespace CPlusPlus;
PCHManager *PCHManager::m_instance = 0;
PCHManager::PCHManager(QObject *parent)
: QObject(parent)
{
Q_ASSERT(!m_instance);
m_instance = this;
QObject *msgMgr = Core::MessageManager::instance();
connect(this, SIGNAL(pchMessage(QString, Core::MessageManager::PrintToOutputPaneFlags)),
msgMgr, SLOT(write(QString, Core::MessageManager::PrintToOutputPaneFlags)));
connect(&m_pchGenerationWatcher, SIGNAL(finished()),
this, SLOT(updateActivePCHFiles()));
}
PCHManager::~PCHManager()
{
Q_ASSERT(m_instance);
m_instance = 0;
qDeleteAll(m_projectSettings.values());
m_projectSettings.clear();
}
PCHManager *PCHManager::instance()
{
return m_instance;
}
PchInfo::Ptr PCHManager::pchInfo(const ProjectPart::Ptr &projectPart) const
{
QMutexLocker locker(&m_mutex);
return m_activePCHFiles[projectPart];
}
ClangProjectSettings *PCHManager::settingsForProject(ProjectExplorer::Project *project)
{
QMutexLocker locker(&m_mutex);
ClangProjectSettings *cps = m_projectSettings.value(project);
if (!cps) {
cps = new ClangProjectSettings(project);
m_projectSettings.insert(project, cps);
cps->pullSettings();
connect(cps, SIGNAL(pchSettingsChanged()),
this, SLOT(clangProjectSettingsChanged()));
}
return cps;
}
void PCHManager::setPCHInfo(const QList<ProjectPart::Ptr> &projectParts,
const PchInfo::Ptr &pchInfo,
const QPair<bool, QStringList> &msgs)
{
QMutexLocker locker(&m_mutex);
foreach (ProjectPart::Ptr pPart, projectParts)
m_activePCHFiles[pPart] = pchInfo;
if (pchInfo) {
if (msgs.first) {
if (!pchInfo->fileName().isEmpty())
emit pchMessage(tr("Successfully generated PCH file \"%1\".").arg(
pchInfo->fileName()), Core::MessageManager::Silent);
} else {
emit pchMessage(tr("Failed to generate PCH file \"%1\".").arg(
pchInfo->fileName()), Core::MessageManager::Silent);
}
if (!msgs.second.isEmpty())
emit pchMessage(msgs.second.join(QLatin1String("\n")), Core::MessageManager::Flash);
}
}
void PCHManager::clangProjectSettingsChanged()
{
ClangProjectSettings *cps = qobject_cast<ClangProjectSettings *>(sender());
if (!cps)
return;
onProjectPartsUpdated(cps->project());
}
void PCHManager::onAboutToRemoveProject(ProjectExplorer::Project *project)
{
Q_UNUSED(project);
// we cannot ask the ModelManager for the parts, because, depending on
// the order of signal delivery, it might already have wiped any information
// about the project.
updateActivePCHFiles();
}
void PCHManager::onProjectPartsUpdated(ProjectExplorer::Project *project)
{
ClangProjectSettings *cps = settingsForProject(project);
Q_ASSERT(cps);
CppTools::CppModelManagerInterface *mmi = CppTools::CppModelManagerInterface::instance();
const QList<ProjectPart::Ptr> projectParts = mmi->projectInfo(
cps->project()).projectParts();
updatePchInfo(cps, projectParts);
emit pchInfoUpdated();
}
void PCHManager::updatePchInfo(ClangProjectSettings *cps,
const QList<ProjectPart::Ptr> &projectParts)
{
if (m_pchGenerationWatcher.isRunning()) {
// m_pchGenerationWatcher.cancel();
m_pchGenerationWatcher.waitForFinished();
}
QFuture<void> future = QtConcurrent::run(&PCHManager::doPchInfoUpdate,
cps->pchUsage(),
cps->customPchFile(),
projectParts);
m_pchGenerationWatcher.setFuture(future);
Core::ProgressManager::addTask(future, tr("Precompiling..."), "Key.Tmp.Precompiling");
}
namespace {
bool hasObjCFiles(const CppTools::ProjectPart::Ptr &projectPart)
{
foreach (const CppTools::ProjectFile &file, projectPart->files) {
switch (file.kind) {
case CppTools::ProjectFile::ObjCHeader:
case CppTools::ProjectFile::ObjCSource:
case CppTools::ProjectFile::ObjCXXHeader:
case CppTools::ProjectFile::ObjCXXSource:
return true;
default:
break;
}
}
return false;
}
bool hasCppFiles(const CppTools::ProjectPart::Ptr &projectPart)
{
foreach (const CppTools::ProjectFile &file, projectPart->files) {
switch (file.kind) {
case CppTools::ProjectFile::CudaSource:
case CppTools::ProjectFile::CXXHeader:
case CppTools::ProjectFile::CXXSource:
case CppTools::ProjectFile::OpenCLSource:
case CppTools::ProjectFile::ObjCXXHeader:
case CppTools::ProjectFile::ObjCXXSource:
return true;
default:
break;
}
}
return false;
}
CppTools::ProjectFile::Kind getPrefixFileKind(bool hasObjectiveC, bool hasCPlusPlus)
{
if (hasObjectiveC && hasCPlusPlus)
return CppTools::ProjectFile::ObjCXXHeader;
else if (hasObjectiveC)
return CppTools::ProjectFile::ObjCHeader;
else if (hasCPlusPlus)
return CppTools::ProjectFile::CXXHeader;
return CppTools::ProjectFile::CHeader;
}
}
void PCHManager::doPchInfoUpdate(QFutureInterface<void> &future,
ClangProjectSettings::PchUsage pchUsage,
const QString customPchFile,
const QList<ProjectPart::Ptr> projectParts)
{
PCHManager *pchManager = PCHManager::instance();
// qDebug() << "switching to" << pchUsage;
if (pchUsage == ClangProjectSettings::PchUse_None
|| (pchUsage == ClangProjectSettings::PchUse_Custom && customPchFile.isEmpty())) {
future.setProgressRange(0, 2);
Core::MessageManager::write(QLatin1String("updatePchInfo: switching to none"),
Core::MessageManager::Silent);
PchInfo::Ptr emptyPch = PchInfo::createEmpty();
pchManager->setPCHInfo(projectParts, emptyPch, qMakePair(true, QStringList()));
future.setProgressValue(1);
} else if (pchUsage == ClangProjectSettings::PchUse_BuildSystem_Fuzzy) {
Core::MessageManager::write(
QLatin1String("updatePchInfo: switching to build system (fuzzy)"),
Core::MessageManager::Silent);
QHash<QString, QSet<QString> > includes, frameworks;
QHash<QString, QSet<QByteArray> > definesPerPCH;
QHash<QString, bool> objc;
QHash<QString, bool> cplusplus;
QHash<QString, ProjectPart::QtVersion> qtVersions;
QHash<QString, ProjectPart::CVersion> cVersions;
QHash<QString, ProjectPart::CXXVersion> cxxVersions;
QHash<QString, ProjectPart::CXXExtensions> cxxExtensionsMap;
QHash<QString, QList<ProjectPart::Ptr> > inputToParts;
foreach (const ProjectPart::Ptr &projectPart, projectParts) {
if (projectPart->precompiledHeaders.isEmpty())
continue;
const QString &pch = projectPart->precompiledHeaders.first(); // TODO: support more than 1 PCH file.
if (!QFile(pch).exists())
continue;
inputToParts[pch].append(projectPart);
includes[pch].unite(QSet<QString>::fromList(projectPart->includePaths));
frameworks[pch].unite(QSet<QString>::fromList(projectPart->frameworkPaths));
cVersions[pch] = std::max(cVersions.value(pch, ProjectPart::C89), projectPart->cVersion);
cxxVersions[pch] = std::max(cxxVersions.value(pch, ProjectPart::CXX98), projectPart->cxxVersion);
cxxExtensionsMap[pch] = cxxExtensionsMap[pch] | projectPart->cxxExtensions;
if (hasObjCFiles(projectPart))
objc[pch] = true;
if (hasCppFiles(projectPart))
cplusplus[pch] = true;
QSet<QByteArray> projectDefines = QSet<QByteArray>::fromList(projectPart->toolchainDefines.split('\n'));
QMutableSetIterator<QByteArray> iter(projectDefines);
while (iter.hasNext()){
QByteArray v = iter.next();
if (v.startsWith("#define _") || v.isEmpty()) // TODO: see ProjectPart::createClangOptions
iter.remove();
}
projectDefines.unite(QSet<QByteArray>::fromList(projectPart->projectDefines.split('\n')));
if (definesPerPCH.contains(pch)) {
definesPerPCH[pch].intersect(projectDefines);
} else {
definesPerPCH[pch] = projectDefines;
}
qtVersions[pch] = projectPart->qtVersion;
}
future.setProgressRange(0, definesPerPCH.size() + 1);
future.setProgressValue(0);
foreach (const QString &pch, inputToParts.keys()) {
if (future.isCanceled())
return;
ProjectPart::Ptr projectPart(new ProjectPart);
projectPart->qtVersion = qtVersions[pch];
projectPart->cVersion = cVersions[pch];
projectPart->cxxVersion = cxxVersions[pch];
projectPart->cxxExtensions = cxxExtensionsMap[pch];
projectPart->includePaths = includes[pch].toList();
projectPart->frameworkPaths = frameworks[pch].toList();
QList<QByteArray> defines = definesPerPCH[pch].toList();
if (!defines.isEmpty()) {
projectPart->projectDefines = defines[0];
for (int i = 1; i < defines.size(); ++i) {
projectPart->projectDefines += '\n';
projectPart->projectDefines += defines[i];
}
}
CppTools::ProjectFile::Kind prefixFileKind =
getPrefixFileKind(objc.value(pch, false), cplusplus.value(pch, false));
QStringList options = Utils::createClangOptions(projectPart, prefixFileKind);
projectPart.reset();
PchInfo::Ptr pchInfo = pchManager->findMatchingPCH(pch, options, true);
QPair<bool, QStringList> msgs = qMakePair(true, QStringList());
if (pchInfo.isNull()) {
pchInfo = PchInfo::createWithFileName(pch, options, objc[pch]);
msgs = precompile(pchInfo);
}
pchManager->setPCHInfo(inputToParts[pch], pchInfo, msgs);
future.setProgressValue(future.progressValue() + 1);
}
} else if (pchUsage == ClangProjectSettings::PchUse_BuildSystem_Exact) {
future.setProgressRange(0, projectParts.size() + 1);
future.setProgressValue(0);
Core::MessageManager::write(
QLatin1String("updatePchInfo: switching to build system (exact)"),
Core::MessageManager::Silent);
foreach (const ProjectPart::Ptr &projectPart, projectParts) {
if (future.isCanceled())
return;
if (projectPart->precompiledHeaders.isEmpty())
continue;
const QString &pch = projectPart->precompiledHeaders.first(); // TODO: support more than 1 PCH file.
if (!QFile(pch).exists())
continue;
const bool hasObjC = hasObjCFiles(projectPart);
QStringList options = Utils::createClangOptions(
projectPart, getPrefixFileKind(hasObjC, hasCppFiles(projectPart)));
PchInfo::Ptr pchInfo = pchManager->findMatchingPCH(pch, options, false);
QPair<bool, QStringList> msgs = qMakePair(true, QStringList());
if (pchInfo.isNull()) {
pchInfo = PchInfo::createWithFileName(pch, options, hasObjC);
msgs = precompile(pchInfo);
}
pchManager->setPCHInfo(QList<ProjectPart::Ptr>() << projectPart,
pchInfo, msgs);
future.setProgressValue(future.progressValue() + 1);
}
} else if (pchUsage == ClangProjectSettings::PchUse_Custom) {
future.setProgressRange(0, 2);
future.setProgressValue(0);
Core::MessageManager::write(
QLatin1String("updatePchInfo: switching to custom") + customPchFile,
Core::MessageManager::Silent);
QSet<QString> includes, frameworks;
bool objc = false;
bool cplusplus = false;
ProjectPart::Ptr united(new ProjectPart());
united->cxxVersion = ProjectPart::CXX98;
foreach (const ProjectPart::Ptr &projectPart, projectParts) {
includes.unite(QSet<QString>::fromList(projectPart->includePaths));
frameworks.unite(QSet<QString>::fromList(projectPart->frameworkPaths));
united->cVersion = std::max(united->cVersion, projectPart->cVersion);
united->cxxVersion = std::max(united->cxxVersion, projectPart->cxxVersion);
united->qtVersion = std::max(united->qtVersion, projectPart->qtVersion);
objc |= hasObjCFiles(projectPart);
cplusplus |= hasCppFiles(projectPart);
}
united->frameworkPaths = frameworks.toList();
united->includePaths = includes.toList();
QStringList opts = Utils::createClangOptions(
united, getPrefixFileKind(objc, cplusplus));
united.clear();
PchInfo::Ptr pchInfo = pchManager->findMatchingPCH(customPchFile, opts, true);
QPair<bool, QStringList> msgs = qMakePair(true, QStringList());;
if (future.isCanceled())
return;
if (pchInfo.isNull()) {
pchInfo = PchInfo::createWithFileName(customPchFile, opts, objc);
msgs = precompile(pchInfo);
}
pchManager->setPCHInfo(projectParts, pchInfo, msgs);
future.setProgressValue(1);
}
future.setProgressValue(future.progressValue() + 1);
}
PchInfo::Ptr PCHManager::findMatchingPCH(const QString &inputFileName,
const QStringList &options,
bool fuzzyMatching) const
{
QMutexLocker locker(&m_mutex);
if (fuzzyMatching) {
QStringList opts = options;
opts.sort();
foreach (PchInfo::Ptr pchInfo, m_activePCHFiles.values()) {
if (pchInfo->inputFileName() != inputFileName)
continue;
QStringList pchOpts = pchInfo->options();
pchOpts.sort();
if (pchOpts == opts)
return pchInfo;
}
} else {
foreach (PchInfo::Ptr pchInfo, m_activePCHFiles.values())
if (pchInfo->inputFileName() == inputFileName
&& pchInfo->options() == options)
return pchInfo;
}
return PchInfo::Ptr();
}
void PCHManager::updateActivePCHFiles()
{
QMutexLocker locker(&m_mutex);
QSet<ProjectPart::Ptr> activeParts;
CppTools::CppModelManagerInterface *mmi = CppTools::CppModelManagerInterface::instance();
foreach (const CppTools::CppModelManagerInterface::ProjectInfo &pi, mmi->projectInfos())
activeParts.unite(QSet<ProjectPart::Ptr>::fromList(pi.projectParts()));
QList<ProjectPart::Ptr> partsWithPCHFiles = m_activePCHFiles.keys();
foreach (ProjectPart::Ptr pPart, partsWithPCHFiles)
if (!activeParts.contains(pPart))
m_activePCHFiles.remove(pPart);
}

View File

@@ -0,0 +1,100 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef PCHMANAGER_H
#define PCHMANAGER_H
#include "clangprojectsettings.h"
#include "pchinfo.h"
#include <cpptools/cppmodelmanagerinterface.h>
#include <projectexplorer/project.h>
#include <coreplugin/messagemanager.h>
#include <QFutureWatcher>
#include <QHash>
#include <QMutex>
#include <QObject>
namespace ClangCodeModel {
namespace Internal {
class PCHManager: public QObject
{
Q_OBJECT
typedef CppTools::ProjectPart ProjectPart;
static PCHManager *m_instance;
public:
PCHManager(QObject *parent = 0);
virtual ~PCHManager();
static PCHManager *instance();
PchInfo::Ptr pchInfo(const ProjectPart::Ptr &projectPart) const;
ClangProjectSettings *settingsForProject(ProjectExplorer::Project *project);
signals:
void pchInfoUpdated(); // TODO: check if this is used
void pchMessage(const QString &message, Core::MessageManager::PrintToOutputPaneFlags flags);
public slots:
void clangProjectSettingsChanged();
void onAboutToRemoveProject(ProjectExplorer::Project *project);
void onProjectPartsUpdated(ProjectExplorer::Project *project);
private slots:
void updateActivePCHFiles();
private:
void updatePchInfo(ClangProjectSettings *cps,
const QList<ProjectPart::Ptr> &projectParts);
static void doPchInfoUpdate(QFutureInterface<void> &future,
ClangProjectSettings::PchUsage pchUsage,
const QString customPchFile,
const QList<ProjectPart::Ptr> projectParts);
void setPCHInfo(const QList<ProjectPart::Ptr> &projectParts,
const PchInfo::Ptr &pchInfo,
const QPair<bool, QStringList> &msgs);
PchInfo::Ptr findMatchingPCH(const QString &inputFileName, const QStringList &options,
bool fuzzyMatching) const;
private:
mutable QMutex m_mutex;
QHash<ProjectPart::Ptr, PchInfo::Ptr> m_activePCHFiles;
QHash<ProjectExplorer::Project *, ClangProjectSettings *> m_projectSettings;
QFutureWatcher<void> m_pchGenerationWatcher;
};
} // namespace Internal
} // namespace ClangCodeModel
#endif // PCHMANAGER_H

View File

@@ -0,0 +1,103 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "scopedclangoptions.h"
namespace ClangCodeModel {
/**
* @class ClangCodeModel::ScopedClangOptions
* @brief Converts QStringList to raw options, acceptable by clang-c parsing and indexing API
*/
ScopedClangOptions::ScopedClangOptions(const QStringList &options)
: m_size(options.size())
, m_rawOptions(new const char*[options.size()])
{
for (int i = 0 ; i < m_size; ++i)
m_rawOptions[i] = qstrdup(options[i].toUtf8());
}
ScopedClangOptions::~ScopedClangOptions()
{
for (int i = 0; i < m_size; ++i)
delete[] m_rawOptions[i];
delete[] m_rawOptions;
}
const char **ScopedClangOptions::data() const
{
return m_rawOptions;
}
int ScopedClangOptions::size() const
{
return m_size;
}
/**
* @class ClangCodeModel::SharedClangOptions
* @brief Shared wrapper around \a {ClangCodeModel::ScopedClangOptions} ScopedClangOptions
*/
SharedClangOptions::SharedClangOptions()
: d(0)
{
}
SharedClangOptions::SharedClangOptions(const QStringList &options)
: d(new ScopedClangOptions(options))
{
}
/**
* @return Replaces options with new options list
*/
void SharedClangOptions::reloadOptions(const QStringList &options)
{
d = QSharedPointer<ScopedClangOptions>(new ScopedClangOptions(options));
}
/**
* @return Pointer to clang raw options or NULL if uninitialized
*/
const char **SharedClangOptions::data() const
{
return d ? d->data() : 0;
}
/**
* @return Options count or 0 if uninitialized
*/
int SharedClangOptions::size() const
{
return d ? d->size() : 0;
}
} // namespace ClangCodeModel

View File

@@ -0,0 +1,72 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef CLANGCODEMODEL_SCOPEDCLANGOPTIONS_H
#define CLANGCODEMODEL_SCOPEDCLANGOPTIONS_H
#include "../clang_global.h"
#include <QStringList>
#include <QSharedPointer>
namespace ClangCodeModel {
class CLANG_EXPORT ScopedClangOptions
{
public:
ScopedClangOptions(const QStringList &options);
~ScopedClangOptions();
const char **data() const;
int size() const;
private:
void release();
int m_size;
const char **m_rawOptions;
};
class CLANG_EXPORT SharedClangOptions
{
public:
SharedClangOptions();
SharedClangOptions(const QStringList &options);
void reloadOptions(const QStringList &options);
const char **data() const;
int size() const;
private:
QSharedPointer<ScopedClangOptions> d;
};
} // namespace ClangCodeModel
#endif // CLANGCODEMODEL_SCOPEDCLANGOPTIONS_H

View File

@@ -0,0 +1,506 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "semanticmarker.h"
#include "unit.h"
#include "utils_p.h"
#include "cxraii.h"
using namespace ClangCodeModel;
using namespace ClangCodeModel::Internal;
static const unsigned ATTACHED_NOTES_LIMIT = 10;
SemanticMarker::SemanticMarker()
{
}
SemanticMarker::~SemanticMarker()
{
}
QString SemanticMarker::fileName() const
{
if (!m_unit)
return QString();
return m_unit->fileName();
}
void SemanticMarker::setFileName(const QString &fileName)
{
if (this->fileName() == fileName)
return;
QStringList oldOptions;
if (m_unit)
oldOptions = m_unit->compilationOptions();
m_unit.reset(new Unit(fileName));
if (!oldOptions.isEmpty())
m_unit->setCompilationOptions(oldOptions);
unsigned clangOpts = clang_defaultEditingTranslationUnitOptions();
clangOpts |= CXTranslationUnit_Incomplete;
clangOpts |= CXTranslationUnit_DetailedPreprocessingRecord;
clangOpts &= ~CXTranslationUnit_CacheCompletionResults;
m_unit->setManagementOptions(clangOpts);
}
void SemanticMarker::setCompilationOptions(const QStringList &options)
{
Q_ASSERT(m_unit);
if (m_unit->compilationOptions() == options)
return;
m_unit->setCompilationOptions(options);
}
void SemanticMarker::reparse(const UnsavedFiles &unsavedFiles)
{
Q_ASSERT(m_unit);
m_unit->setUnsavedFiles(unsavedFiles);
if (m_unit->isLoaded())
m_unit->reparse();
else
m_unit->parse();
}
/**
* \brief Calculate one or several ranges and append diagnostic for each range
* Extracted from SemanticMarker::diagnostics() to reuse code
*/
static void appendDiagnostic(const CXDiagnostic &diag,
const CXSourceLocation &cxLocation,
Diagnostic::Severity severity,
const QString &spelling,
QList<Diagnostic> &diagnostics)
{
const unsigned rangeCount = clang_getDiagnosticNumRanges(diag);
bool expandLocation = true;
for (unsigned i = 0; i < rangeCount; ++i) {
CXSourceRange r = clang_getDiagnosticRange(diag, i);
const SourceLocation &spellBegin = Internal::getSpellingLocation(clang_getRangeStart(r));
const SourceLocation &spellEnd = Internal::getSpellingLocation(clang_getRangeEnd(r));
unsigned length = spellEnd.offset() - spellBegin.offset();
// File name can be empty due clang bug
if (!spellBegin.fileName().isEmpty()) {
Diagnostic d(severity, spellBegin, length, spelling);
diagnostics.append(d);
expandLocation = false;
}
}
if (expandLocation) {
const SourceLocation &location = Internal::getExpansionLocation(cxLocation);
Diagnostic d(severity, location, 0, spelling);
diagnostics.append(d);
}
}
QList<Diagnostic> SemanticMarker::diagnostics() const
{
QList<Diagnostic> diagnostics;
if (!m_unit || !m_unit->isLoaded())
return diagnostics;
const unsigned diagCount = m_unit->getNumDiagnostics();
for (unsigned i = 0; i < diagCount; ++i) {
ScopedCXDiagnostic diag(m_unit->getDiagnostic(i));
Diagnostic::Severity severity = static_cast<Diagnostic::Severity>(clang_getDiagnosticSeverity(diag));
if (severity == Diagnostic::Ignored || severity == Diagnostic::Note)
continue;
CXSourceLocation cxLocation = clang_getDiagnosticLocation(diag);
QString spelling = Internal::getQString(clang_getDiagnosticSpelling(diag));
// Attach messages with Diagnostic::Note severity
ScopedCXDiagnosticSet cxChildren(clang_getChildDiagnostics(diag));
const unsigned numChildren = clang_getNumDiagnosticsInSet(cxChildren);
const unsigned size = qMin(ATTACHED_NOTES_LIMIT, numChildren);
for (unsigned di = 0; di < size; ++di) {
ScopedCXDiagnostic child(clang_getDiagnosticInSet(cxChildren, di));
spelling.append(QLatin1String("\n "));
spelling.append(Internal::getQString(clang_getDiagnosticSpelling(child)));
}
// Fatal error may occur in another file, but it breaks whole parsing
// Typical fatal error is unresolved #include
if (severity == Diagnostic::Fatal) {
for (unsigned di = 0; di < numChildren; ++di) {
ScopedCXDiagnostic child(clang_getDiagnosticInSet(cxChildren, di));
appendDiagnostic(child, clang_getDiagnosticLocation(child), Diagnostic::Warning, spelling, diagnostics);
}
}
appendDiagnostic(diag, cxLocation, severity, spelling, diagnostics);
}
return diagnostics;
}
QList<TextEditor::BlockRange> SemanticMarker::ifdefedOutBlocks() const
{
QList<TextEditor::BlockRange> blocks;
if (!m_unit || !m_unit->isLoaded())
return blocks;
#if CINDEX_VERSION_MINOR >= 21
CXSourceRangeList *skippedRanges = clang_getSkippedRanges(m_unit->clangTranslationUnit(),
m_unit->getFile());
blocks.reserve(skippedRanges->count);
for (unsigned i = 0; i < skippedRanges->count; ++i) {
const CXSourceRange &r = skippedRanges->ranges[i];
const SourceLocation &spellBegin = Internal::getSpellingLocation(clang_getRangeStart(r));
if (spellBegin.fileName() != fileName())
continue;
const SourceLocation &spellEnd = Internal::getSpellingLocation(clang_getRangeEnd(r));
const int begin = spellBegin.offset() + 1;
const int end = spellEnd.offset() - spellEnd.column();
blocks.append(TextEditor::BlockRange(begin, end));
}
clang_disposeSourceRangeList(skippedRanges);
#endif
return blocks;
}
namespace {
static void add(QList<SourceMarker> &markers,
const CXSourceRange &extent,
SourceMarker::Kind kind)
{
CXSourceLocation start = clang_getRangeStart(extent);
CXSourceLocation end = clang_getRangeEnd(extent);
const SourceLocation &location = Internal::getExpansionLocation(start);
const SourceLocation &locationEnd = Internal::getExpansionLocation(end);
if (location.offset() < locationEnd.offset()) {
const unsigned length = locationEnd.offset() - location.offset();
markers.append(SourceMarker(location, length, kind));
}
}
/**
* @brief Selects correct highlighting for cursor that is reference
* @return SourceMarker::Unknown if cannot select highlighting
*/
static SourceMarker::Kind getKindByReferencedCursor(const CXCursor &cursor)
{
const CXCursor referenced = clang_getCursorReferenced(cursor);
switch (clang_getCursorKind(referenced)) {
case CXCursor_EnumConstantDecl:
return SourceMarker::Enumeration;
case CXCursor_FieldDecl:
case CXCursor_ObjCIvarDecl:
case CXCursor_ObjCPropertyDecl:
return SourceMarker::Field;
case CXCursor_FunctionDecl:
case CXCursor_FunctionTemplate:
case CXCursor_Constructor:
return SourceMarker::Function;
case CXCursor_VarDecl:
case CXCursor_ParmDecl:
case CXCursor_NonTypeTemplateParameter:
return SourceMarker::Local;
case CXCursor_CXXMethod:
if (clang_CXXMethod_isVirtual(referenced))
return SourceMarker::VirtualMethod;
else
return SourceMarker::Function;
case CXCursor_ObjCClassMethodDecl:
case CXCursor_ObjCInstanceMethodDecl:
// calling method as property, e.h. "layer.shouldRasterize = YES"
return SourceMarker::Field;
case CXCursor_UnexposedDecl:
// NSObject "self" method which is a pseudo keyword
if (clang_getCursorLanguage(referenced) == CXLanguage_ObjC)
return SourceMarker::PseudoKeyword;
break;
default:
break;
}
return SourceMarker::Unknown;
}
static const QSet<QString> ObjcPseudoKeywords = QSet<QString>()
<< QLatin1String("end")
<< QLatin1String("try")
<< QLatin1String("defs")
<< QLatin1String("throw")
<< QLatin1String("class")
<< QLatin1String("catch")
<< QLatin1String("encode")
<< QLatin1String("public")
<< QLatin1String("dynamic")
<< QLatin1String("finally")
<< QLatin1String("package")
<< QLatin1String("private")
<< QLatin1String("optional")
<< QLatin1String("property")
<< QLatin1String("protocol")
<< QLatin1String("required")
<< QLatin1String("selector")
<< QLatin1String("interface")
<< QLatin1String("protected")
<< QLatin1String("synthesize")
<< QLatin1String("not_keyword")
<< QLatin1String("synchronized")
<< QLatin1String("implementation")
<< QLatin1String("compatibility_alias")
;
} // Anonymous namespace
/**
* @brief SemanticMarker::sourceMarkersInRange
* @param firstLine - first line where to generate highlighting markers
* @param lastLine - last line where to generate highlighting markers
*
* There still two kinds of problems:
* - clang_annotateTokens() can return wrong cursor, and it's normal behavior
* - some cases no handled
*
* Problems caused by wrong cursors:
* - range-based for from C++ 2011
* - identifiers in some compound statements have type DeclStmt
* or CompoundStmt which refers to top-level construction.
* - CXCursor_ObjCIvarDecl mapped to field, but instance variable have
* incorrect cursor kind if it declared in private interface
* @interface MyApplication() {
* NSArray* _items;
* }
*
* Missed cases:
* - global variables highlighted as locals
* - appropriate marker had not been selected for listed cursors:
* CXCursor_ObjCProtocolExpr, CXCursor_ObjCEncodeExpr,
* CXCursor_ObjCDynamicDecl, CXCursor_ObjCBridgedCastExpr,
* CXCursor_ObjCSuperClassRef
* - template members of template classes&functions always highlighted
* as members, even if they are functions - no way to differ found.
* - @1, @{}, @[]
*/
QList<SourceMarker> SemanticMarker::sourceMarkersInRange(unsigned firstLine,
unsigned lastLine)
{
Q_ASSERT(m_unit);
QList<SourceMarker> result;
if (!m_unit->isLoaded())
return result;
// Highlighting called asynchronously, and a few lines at the end can be deleted for this time.
CXSourceRange unitRange = clang_getCursorExtent(m_unit->getTranslationUnitCursor());
SourceLocation unitEnd = getExpansionLocation(clang_getRangeEnd(unitRange));
if (lastLine > unitEnd.line())
lastLine = unitEnd.line();
if (firstLine > lastLine)
return result;
IdentifierTokens idTokens(*m_unit, firstLine, lastLine);
const CXSourceRange *atTokenExtent = 0;
for (unsigned i = 0; i < idTokens.count(); ++i) {
const CXToken &tok = idTokens.token(i);
CXTokenKind kind = clang_getTokenKind(tok);
if (atTokenExtent) {
if (CXToken_Literal == kind) {
if (m_unit->getTokenSpelling(tok).startsWith(QLatin1Char('"')))
add(result, *atTokenExtent, SourceMarker::ObjCString);
atTokenExtent = 0;
continue;
} else {
add(result, *atTokenExtent, SourceMarker::PseudoKeyword);
atTokenExtent = 0;
}
}
const CXSourceRange &tokenExtent = idTokens.extent(i);
if (CXToken_Keyword == kind) {
QString spell = m_unit->getTokenSpelling(tok);
if (ObjcPseudoKeywords.contains(spell))
add(result, tokenExtent, SourceMarker::PseudoKeyword);
continue;
}
if (CXToken_Punctuation == kind) {
static const QLatin1String at("@");
if (m_unit->getTokenSpelling(tok) == at)
atTokenExtent = &tokenExtent;
continue;
}
if (CXToken_Identifier != kind)
continue;
const CXCursor &cursor = idTokens.cursor(i);
const CXCursorKind cursorKind = clang_getCursorKind(cursor);
if (clang_isInvalid(cursorKind))
continue;
switch (cursorKind) {
case CXCursor_EnumConstantDecl:
add(result, tokenExtent, SourceMarker::Enumeration);
break;
case CXCursor_ClassDecl:
case CXCursor_UnionDecl:
case CXCursor_ClassTemplate:
case CXCursor_ClassTemplatePartialSpecialization:
case CXCursor_EnumDecl:
case CXCursor_Namespace:
case CXCursor_NamespaceRef:
case CXCursor_NamespaceAlias:
case CXCursor_StructDecl:
case CXCursor_TemplateRef:
case CXCursor_TypeRef:
case CXCursor_TypedefDecl:
case CXCursor_Constructor:
case CXCursor_TemplateTypeParameter:
case CXCursor_TemplateTemplateParameter:
case CXCursor_UnexposedDecl: /* friend class MyClass; */
add(result, tokenExtent, SourceMarker::Type);
break;
case CXCursor_ParmDecl:
case CXCursor_VariableRef:
case CXCursor_VarDecl:
case CXCursor_NonTypeTemplateParameter:
add(result, tokenExtent, SourceMarker::Local);
break;
case CXCursor_MemberRefExpr:
case CXCursor_MemberRef:
case CXCursor_DeclRefExpr:
case CXCursor_CallExpr: {
SourceMarker::Kind kind = getKindByReferencedCursor(cursor);
if (kind == SourceMarker::Unknown && cursorKind == CXCursor_MemberRefExpr) {
/* template class member in template function */
kind = SourceMarker::Field;
}
if (kind != SourceMarker::Unknown)
add(result, tokenExtent, kind);
} break;
case CXCursor_FieldDecl:
add(result, tokenExtent, SourceMarker::Field);
break;
case CXCursor_Destructor:
case CXCursor_CXXMethod: {
if (clang_CXXMethod_isVirtual(cursor))
add(result, tokenExtent, SourceMarker::VirtualMethod);
else
add(result, tokenExtent, SourceMarker::Function);
} break;
case CXCursor_CXXOverrideAttr:
case CXCursor_CXXFinalAttr:
case CXCursor_AnnotateAttr: // 'annotate' in '__attribute__((annotate("AnyComment")))'
case CXCursor_UnexposedAttr: // 'align' in '__declspec(align(8))'
add(result, tokenExtent, SourceMarker::PseudoKeyword);
break;
case CXCursor_FunctionDecl:
case CXCursor_FunctionTemplate:
case CXCursor_OverloadedDeclRef:
add(result, tokenExtent, SourceMarker::Function);
break;
case CXCursor_ObjCInstanceMethodDecl:
case CXCursor_ObjCClassMethodDecl:
case CXCursor_ObjCSelectorExpr:
add(result, tokenExtent, SourceMarker::ObjectiveCMessage);
break;
case CXCursor_ObjCMessageExpr: {
static const QLatin1String super("super");
if (m_unit->getTokenSpelling(tok) == super)
add(result, tokenExtent, SourceMarker::PseudoKeyword);
else
add(result, tokenExtent, SourceMarker::ObjectiveCMessage);
} break;
case CXCursor_ObjCCategoryDecl:
case CXCursor_ObjCCategoryImplDecl:
case CXCursor_ObjCImplementationDecl:
case CXCursor_ObjCInterfaceDecl:
case CXCursor_ObjCProtocolDecl:
case CXCursor_ObjCProtocolRef:
case CXCursor_ObjCClassRef:
case CXCursor_ObjCSuperClassRef:
case CXCursor_TypeAliasDecl: // C++11 type alias: 'using value_t = T'
add(result, tokenExtent, SourceMarker::Type);
break;
case CXCursor_ObjCSynthesizeDecl:
case CXCursor_ObjCDynamicDecl:
case CXCursor_ObjCPropertyDecl:
case CXCursor_ObjCIvarDecl:
add(result, tokenExtent, SourceMarker::Field);
break;
case CXCursor_MacroDefinition:
case CXCursor_MacroExpansion:
add(result, tokenExtent, SourceMarker::Macro);
break;
case CXCursor_LabelRef:
case CXCursor_LabelStmt:
add(result, tokenExtent, SourceMarker::Label);
break;
default:
break;
}
}
return result;
}
Unit SemanticMarker::unit() const
{
return *m_unit;
}

View File

@@ -0,0 +1,90 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef CLANG_SEMANTICMARKER_H
#define CLANG_SEMANTICMARKER_H
#include "clang_global.h"
#include "diagnostic.h"
#include "fastindexer.h"
#include "sourcemarker.h"
#include "utils.h"
#include <texteditor/itexteditor.h>
#include <QMutex>
#include <QScopedPointer>
#include <QSharedPointer>
#include <QString>
#include <QStringList>
namespace ClangCodeModel {
namespace Internal {
class Unit;
}
class CLANG_EXPORT SemanticMarker
{
Q_DISABLE_COPY(SemanticMarker)
public:
typedef QSharedPointer<SemanticMarker> Ptr;
public:
SemanticMarker();
~SemanticMarker();
QMutex *mutex() const
{ return &m_mutex; }
QString fileName() const;
void setFileName(const QString &fileName);
void setCompilationOptions(const QStringList &options);
void reparse(const Internal::UnsavedFiles &unsavedFiles);
QList<Diagnostic> diagnostics() const;
QList<TextEditor::BlockRange> ifdefedOutBlocks() const;
QList<SourceMarker> sourceMarkersInRange(unsigned firstLine,
unsigned lastLine);
Internal::Unit unit() const;
private:
mutable QMutex m_mutex;
QScopedPointer<Internal::Unit> m_unit;
};
} // namespace ClangCodeModel
#endif // CLANG_SEMANTICMARKER_H

View File

@@ -0,0 +1,79 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "sourcelocation.h"
using namespace ClangCodeModel;
SourceLocation::SourceLocation()
: m_line(0)
, m_column(0)
, m_offset(0)
{}
SourceLocation::SourceLocation(const QString &fileName,
unsigned line,
unsigned column,
unsigned offset)
: m_fileName(fileName)
, m_line(line)
, m_column(column)
, m_offset(offset)
{}
namespace ClangCodeModel {
bool operator==(const SourceLocation &a, const SourceLocation &b)
{
return a.line() == b.line()
&& a.column() == b.column()
&& a.offset() == b.offset()
&& a.fileName() == b.fileName()
;
}
bool operator!=(const SourceLocation &a, const SourceLocation &b)
{
return !(a == b);
}
QDebug operator<<(QDebug dbg, const SourceLocation &location)
{
dbg.nospace() << location.fileName()
<< " ["
<< location.line()
<< ":"
<< location.column()
<< "("
<< location.offset()
<< ")]";
return dbg.space();
}
} // ClangCodeModel

View File

@@ -0,0 +1,69 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef SOURCELOCATION_H
#define SOURCELOCATION_H
#include "clang_global.h"
#include <QtCore/QString>
#include <QtCore/QDebug>
namespace ClangCodeModel {
class CLANG_EXPORT SourceLocation
{
public:
SourceLocation();
SourceLocation(const QString &fileName,
unsigned line = 0,
unsigned column = 0,
unsigned offset = 0);
bool isNull() const { return m_fileName.isEmpty(); }
const QString &fileName() const { return m_fileName; }
unsigned line() const { return m_line; }
unsigned column() const { return m_column; }
unsigned offset() const { return m_offset; }
private:
QString m_fileName;
unsigned m_line;
unsigned m_column;
unsigned m_offset;
};
bool operator==(const SourceLocation &a, const SourceLocation &b);
bool operator!=(const SourceLocation &a, const SourceLocation &b);
QDebug operator<<(QDebug dbg, const SourceLocation &location);
} // ClangCodeModel
#endif // SOURCELOCATION_H

View File

@@ -0,0 +1,41 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "sourcemarker.h"
using namespace ClangCodeModel;
SourceMarker::SourceMarker()
: m_length(0), m_kind(Unknown)
{}
SourceMarker::SourceMarker(const SourceLocation &location, unsigned length, Kind kind)
: m_loc(location), m_length(length), m_kind(kind)
{
}

View File

@@ -0,0 +1,97 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef CLANG_SOURCEMARKER_H
#define CLANG_SOURCEMARKER_H
#include "clang_global.h"
#include "sourcelocation.h"
namespace ClangCodeModel {
class CLANG_EXPORT SourceMarker
{
public: // TODO: remove this, it's about the same as the TextEditor::SemanticHighlighter::Result
enum Kind {
Unknown = 0,
Type = 1,
Local,
Field,
Enumeration,
VirtualMethod,
Label,
Macro,
Function,
PseudoKeyword,
ObjCString,
ObjectiveCMessage = VirtualMethod
};
SourceMarker();
SourceMarker(const SourceLocation &location,
unsigned length,
Kind kind);
bool isValid() const
{ return m_loc.line() != 0; }
bool isInvalid() const
{ return m_loc.line() == 0; }
const SourceLocation &location() const
{ return m_loc; }
unsigned length() const
{ return m_length; }
Kind kind() const
{ return m_kind; }
bool lessThan(const SourceMarker &other) const
{
if (m_loc.line() != other.m_loc.line())
return m_loc.line() < other.m_loc.line();
if (m_loc.column() != other.m_loc.column())
return m_loc.column() < other.m_loc.column();
return m_length < other.m_length;
}
private:
SourceLocation m_loc;
unsigned m_length;
Kind m_kind;
};
CLANG_EXPORT inline bool operator<(const SourceMarker &one, const SourceMarker &two)
{ return one.lessThan(two); }
} // namespace Clang
#endif // CLANG_SOURCEMARKER_H

View File

@@ -0,0 +1,117 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "symbol.h"
#include <cplusplus/Icons.h>
using namespace ClangCodeModel;
Symbol::Symbol()
: m_kind(Unknown)
{}
Symbol::Symbol(const QString &name,
const QString &qualification,
Kind type,
const SourceLocation &location)
: m_name(name)
, m_qualification(qualification)
, m_location(location)
, m_kind(type)
{}
QIcon Symbol::iconForSymbol() const
{
CPlusPlus::Icons icons;
switch (m_kind) {
case Enum:
return icons.iconForType(CPlusPlus::Icons::EnumIconType);
case Class:
return icons.iconForType(CPlusPlus::Icons::ClassIconType);
case Method:
case Function:
case Declaration:
case Constructor:
case Destructor:
return icons.iconForType(CPlusPlus::Icons::FuncPublicIconType);
default:
return icons.iconForType(CPlusPlus::Icons::UnknownIconType);
}
}
namespace ClangCodeModel {
QDataStream &operator<<(QDataStream &stream, const Symbol &symbol)
{
stream << symbol.m_name
<< symbol.m_qualification
<< symbol.m_location.fileName()
<< (quint32)symbol.m_location.line()
<< (quint16)symbol.m_location.column()
<< (quint32)symbol.m_location.offset()
<< (qint8)symbol.m_kind;
return stream;
}
QDataStream &operator>>(QDataStream &stream, Symbol &symbol)
{
QString fileName;
quint32 line;
quint16 column;
quint32 offset;
quint8 kind;
stream >> symbol.m_name
>> symbol.m_qualification
>> fileName
>> line
>> column
>> offset
>> kind;
symbol.m_location = SourceLocation(fileName, line, column, offset);
symbol.m_kind = Symbol::Kind(kind);
return stream;
}
bool operator==(const Symbol &a, const Symbol &b)
{
return a.m_name == b.m_name
&& a.m_qualification == b.m_qualification
&& a.m_location == b.m_location
&& a.m_kind == b.m_kind;
}
bool operator!=(const Symbol &a, const Symbol &b)
{
return !(a == b);
}
} // ClangCodeModel

View File

@@ -0,0 +1,77 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef INDEXEDSYMBOLINFO_H
#define INDEXEDSYMBOLINFO_H
#include "sourcelocation.h"
#include <QString>
#include <QDataStream>
#include <QIcon>
namespace ClangCodeModel {
class Symbol
{
public:
enum Kind {
Enum,
Class,
Method, // A member-function.
Function, // A free-function (global or within a namespace).
Declaration,
Constructor,
Destructor,
Unknown
};
Symbol();
Symbol(const QString &name,
const QString &qualification,
Kind type,
const SourceLocation &location);
QString m_name;
QString m_qualification;
SourceLocation m_location;
Kind m_kind;
QIcon iconForSymbol() const;
};
QDataStream &operator<<(QDataStream &stream, const Symbol &symbol);
QDataStream &operator>>(QDataStream &stream, Symbol &symbol);
bool operator==(const Symbol &a, const Symbol &b);
bool operator!=(const Symbol &a, const Symbol &b);
} // Clang
#endif // INDEXEDSYMBOLINFO_H

View File

@@ -0,0 +1,20 @@
<RCC>
<qresource prefix="/unittests/ClangCodeModel">
<file>cxx_regression_1.cpp</file>
<file>cxx_regression_2.cpp</file>
<file>cxx_regression_3.cpp</file>
<file>cxx_regression_4.cpp</file>
<file>cxx_regression_5.cpp</file>
<file>cxx_regression_6.cpp</file>
<file>cxx_regression_7.cpp</file>
<file>cxx_regression_8.cpp</file>
<file>cxx_regression_9.cpp</file>
<file>cxx_snippets_1.cpp</file>
<file>cxx_snippets_2.cpp</file>
<file>cxx_snippets_3.cpp</file>
<file>cxx_snippets_4.cpp</file>
<file>objc_messages_1.mm</file>
<file>objc_messages_2.mm</file>
<file>objc_messages_3.mm</file>
</qresource>
</RCC>

View File

@@ -0,0 +1,392 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
/**
* @file clangcompletion_test.cpp
* @brief Performs test for C/C++ code completion
*
* All test cases given as strings with @ character that points to completion
* location.
*/
#ifdef WITH_TESTS
// Disabled because there still no tool to detect system Objective-C headers
#define ENABLE_OBJC_TESTS 0
#include <QtTest>
#include <QDebug>
#undef interface // Canceling "#DEFINE interface struct" on Windows
#include "completiontesthelper.h"
#include "../clangcodemodelplugin.h"
using namespace ClangCodeModel;
using namespace ClangCodeModel::Internal;
////////////////////////////////////////////////////////////////////////////////
// Test cases
/**
* \defgroup Regression tests
*
* This group tests possible regressions in non-standard completion chunks
* handling: for example, macro arguments and clang's code snippets.
*
* @{
*/
void ClangCodeModelPlugin::test_CXX_regressions()
{
QFETCH(QString, file);
QFETCH(QStringList, unexpected);
QFETCH(QStringList, mustHave);
CompletionTestHelper helper;
helper << file;
QStringList proposals = helper.codeCompleteTexts();
foreach (const QString &p, unexpected)
QTEST_ASSERT(false == proposals.contains(p));
foreach (const QString &p, mustHave)
QTEST_ASSERT(true == proposals.contains(p));
}
void ClangCodeModelPlugin::test_CXX_regressions_data()
{
QTest::addColumn<QString>("file");
QTest::addColumn<QStringList>("unexpected");
QTest::addColumn<QStringList>("mustHave");
QString file;
QStringList unexpected;
QStringList mustHave;
file = QLatin1String("cxx_regression_1.cpp");
mustHave << QLatin1String("sqr");
mustHave << QLatin1String("~Math");
unexpected << QLatin1String("operator=");
QTest::newRow("case 1: method call completion") << file << unexpected << mustHave;
mustHave.clear();
unexpected.clear();
file = QLatin1String("cxx_regression_2.cpp");
unexpected << QLatin1String("i_second");
unexpected << QLatin1String("c_second");
unexpected << QLatin1String("f_second");
mustHave << QLatin1String("i_first");
mustHave << QLatin1String("c_first");
QTest::newRow("case 2: multiple anonymous structs") << file << unexpected << mustHave;
mustHave.clear();
unexpected.clear();
file = QLatin1String("cxx_regression_3.cpp");
mustHave << QLatin1String("i8");
mustHave << QLatin1String("i64");
mustHave << QLatin1String("~Priv");
unexpected << QLatin1String("operator=");
QTest::newRow("case 3: nested class resolution") << file << unexpected << mustHave;
mustHave.clear();
unexpected.clear();
file = QLatin1String("cxx_regression_4.cpp");
mustHave << QLatin1String("action");
QTest::newRow("case 4: local (in function) class resolution") << file << unexpected << mustHave;
mustHave.clear();
unexpected.clear();
file = QLatin1String("cxx_regression_5.cpp");
mustHave << QLatin1String("doB");
unexpected << QLatin1String("doA");
QTest::newRow("case 5: nested template class resolution") << file << unexpected << mustHave;
mustHave.clear();
unexpected.clear();
file = QLatin1String("cxx_regression_6.cpp");
mustHave << QLatin1String("OwningPtr");
QTest::newRow("case 6: using particular symbol from namespace") << file << unexpected << mustHave;
mustHave.clear();
unexpected.clear();
file = QLatin1String("cxx_regression_7.cpp");
mustHave << QLatin1String("dataMember");
mustHave << QLatin1String("anotherMember");
QTest::newRow("case 7: template class inherited from template parameter") << file << unexpected << mustHave;
mustHave.clear();
unexpected.clear();
file = QLatin1String("cxx_regression_8.cpp");
mustHave << QLatin1String("utils::");
unexpected << QLatin1String("utils");
QTest::newRow("case 8: namespace completion in function body") << file << unexpected << mustHave;
mustHave.clear();
unexpected.clear();
file = QLatin1String("cxx_regression_9.cpp");
mustHave << QLatin1String("EnumScoped::Value1");
mustHave << QLatin1String("EnumScoped::Value2");
mustHave << QLatin1String("EnumScoped::Value3");
unexpected << QLatin1String("Value1");
unexpected << QLatin1String("EnumScoped");
QTest::newRow("case 9: c++11 enum class, value used in switch and 'case' completed")
<< file << unexpected << mustHave;
mustHave.clear();
unexpected.clear();
}
void ClangCodeModelPlugin::test_CXX_snippets()
{
QFETCH(QString, file);
QFETCH(QStringList, texts);
QFETCH(QStringList, snippets);
Q_ASSERT(texts.size() == snippets.size());
CompletionTestHelper helper;
helper << file;
QList<CodeCompletionResult> proposals = helper.codeComplete();
for (int i = 0, n = texts.size(); i < n; ++i) {
const QString &text = texts[i];
const QString &snippet = snippets[i];
const QString snippetError =
QLatin1String("Text and snippet mismatch: text '") + text
+ QLatin1String("', snippet '") + snippet
+ QLatin1String("', got snippet '%1'");
bool hasText = false;
foreach (const CodeCompletionResult &ccr, proposals) {
if (ccr.text() != text)
continue;
hasText = true;
QVERIFY2(snippet == ccr.snippet(), snippetError.arg(ccr.snippet()).toAscii());
}
const QString textError(QLatin1String("Text not found:") + text);
QVERIFY2(hasText, textError.toAscii());
}
}
void ClangCodeModelPlugin::test_CXX_snippets_data()
{
QTest::addColumn<QString>("file");
QTest::addColumn<QStringList>("texts");
QTest::addColumn<QStringList>("snippets");
QString file;
QStringList texts;
QStringList snippets;
file = QLatin1String("cxx_snippets_1.cpp");
texts << QLatin1String("reinterpret_cast<type>(expression)");
snippets << QLatin1String("reinterpret_cast<$type$>($expression$)");
texts << QLatin1String("static_cast<type>(expression)");
snippets << QLatin1String("static_cast<$type$>($expression$)");
texts << QLatin1String("new type(expressions)");
snippets << QLatin1String("new $type$($expressions$)");
QTest::newRow("case: snippets for var declaration") << file << texts << snippets;
texts.clear();
snippets.clear();
file = QLatin1String("cxx_snippets_2.cpp");
texts << QLatin1String("private");
snippets << QLatin1String("");
texts << QLatin1String("protected");
snippets << QLatin1String("");
texts << QLatin1String("public");
snippets << QLatin1String("");
texts << QLatin1String("friend");
snippets << QLatin1String("");
texts << QLatin1String("virtual");
snippets << QLatin1String("");
texts << QLatin1String("typedef type name");
snippets << QLatin1String("typedef $type$ $name$");
QTest::newRow("case: snippets inside class declaration") << file << texts << snippets;
texts.clear();
snippets.clear();
file = QLatin1String("cxx_snippets_3.cpp");
texts << QLatin1String("List");
snippets << QLatin1String("List<$class Item$>");
texts << QLatin1String("Tuple");
snippets << QLatin1String("Tuple<$class First$, $class Second$, $typename Third$>");
QTest::newRow("case: template class insertion as snippet") << file << texts << snippets;
texts.clear();
snippets.clear();
file = QLatin1String("cxx_snippets_4.cpp");
texts << QLatin1String("clamp");
snippets << QLatin1String("");
texts << QLatin1String("perform");
snippets << QLatin1String("perform<$class T$>");
QTest::newRow("case: template function insertion as snippet") << file << texts << snippets;
texts.clear();
snippets.clear();
}
void ClangCodeModelPlugin::test_ObjC_hints()
{
QFETCH(QString, file);
QFETCH(QStringList, texts);
QFETCH(QStringList, snippets);
QFETCH(QStringList, hints);
Q_ASSERT(texts.size() == snippets.size());
Q_ASSERT(texts.size() == hints.size());
CompletionTestHelper helper;
helper << file;
QList<CodeCompletionResult> proposals = helper.codeComplete();
for (int i = 0, n = texts.size(); i < n; ++i) {
const QString &text = texts[i];
const QString &snippet = snippets[i];
const QString &hint = hints[i];
const QString snippetError =
QLatin1String("Text and snippet mismatch: text '") + text
+ QLatin1String("', snippet '") + snippet
+ QLatin1String("', got snippet '%1'");
const QString hintError =
QLatin1String("Text and hint mismatch: text '") + text
+ QLatin1String("', hint\n'") + hint
+ QLatin1String(", got hint\n'%1'");
bool hasText = false;
QStringList texts;
foreach (const CodeCompletionResult &ccr, proposals) {
texts << ccr.text();
if (ccr.text() != text)
continue;
hasText = true;
QVERIFY2(snippet == ccr.snippet(), snippetError.arg(ccr.snippet()).toAscii());
QVERIFY2(hint == ccr.hint(), hintError.arg(ccr.hint()).toAscii());
}
const QString textError(QString::fromLatin1("Text '%1' not found in set %2")
.arg(text).arg(texts.join(QLatin1Char(','))));
QVERIFY2(hasText, textError.toAscii());
}
}
static QString makeObjCHint(const char *cHintPattern)
{
QString hintPattern(QString::fromUtf8(cHintPattern));
QStringList lines = hintPattern.split(QLatin1Char('\n'));
QString hint = QLatin1String("<p>");
bool prependNewline = false;
foreach (const QString &line, lines) {
if (prependNewline)
hint += QLatin1String("<br/>");
prependNewline = true;
int i = 0;
while (i < line.size() && line[i] == QLatin1Char(' ')) {
++i;
hint += QLatin1String("&nbsp;");
}
hint += line.mid(i);
}
hint += QLatin1String("</p>");
return hint;
}
void ClangCodeModelPlugin::test_ObjC_hints_data()
{
QTest::addColumn<QString>("file");
QTest::addColumn<QStringList>("texts");
QTest::addColumn<QStringList>("snippets");
QTest::addColumn<QStringList>("hints");
QString file;
QStringList texts;
QStringList snippets;
QStringList hints;
file = QLatin1String("objc_messages_1.mm");
texts << QLatin1String("spectacleQuality:");
snippets << QLatin1String("spectacleQuality:$(bool)$");
hints << makeObjCHint("-(int) spectacleQuality:<b>(bool)</b>");
texts << QLatin1String("desiredAmountForDramaDose:andPersonsCount:");
snippets << QLatin1String("desiredAmountForDramaDose:$(int)$ andPersonsCount:$(int)$");
hints << makeObjCHint("-(int) desiredAmountForDramaDose:<b>(int)</b> \n"
" andPersonsCount:<b>(int)</b>");
QTest::newRow("case: objective-c instance messages call") << file << texts << snippets << hints;
texts.clear();
snippets.clear();
hints.clear();
file = QLatin1String("objc_messages_2.mm");
texts << QLatin1String("eatenAmount");
snippets << QLatin1String("(int) eatenAmount");
hints << makeObjCHint("+(int) eatenAmount");
texts << QLatin1String("desiredAmountForDramaDose:andPersonsCount:");
snippets << QLatin1String("(int) desiredAmountForDramaDose:(int)dose andPersonsCount:(int)count");
hints << makeObjCHint("+(int) desiredAmountForDramaDose:(int)dose \n"
" andPersonsCount:(int)count");
QTest::newRow("case: objective-c class messages in @implementation") << file << texts << snippets << hints;
texts.clear();
snippets.clear();
hints.clear();
file = QLatin1String("objc_messages_3.mm");
texts << QLatin1String("eatenAmount");
snippets << QLatin1String("(int) eatenAmount");
hints << makeObjCHint("-(int) eatenAmount");
texts << QLatin1String("spectacleQuality");
snippets << QLatin1String("(int) spectacleQuality");
hints << makeObjCHint("-(int) spectacleQuality");
texts << QLatin1String("desiredAmountForDramaDose:andPersonsCount:");
snippets << QLatin1String("(int) desiredAmountForDramaDose:(int)dose andPersonsCount:(int)count");
hints << makeObjCHint("-(int) desiredAmountForDramaDose:(int)dose \n"
" andPersonsCount:(int)count");
texts << QLatin1String("initWithOldTracker:");
snippets << QLatin1String("(id) initWithOldTracker:(Bbbb<Aaaa> *)aabb");
hints << makeObjCHint("-(id) initWithOldTracker:(Bbbb&lt;Aaaa&gt; *)aabb");
QTest::newRow("case: objective-c class messages from base class") << file << texts << snippets << hints;
texts.clear();
snippets.clear();
hints.clear();
}
#endif

View File

@@ -0,0 +1,148 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifdef WITH_TESTS
#include "completiontesthelper.h"
#include "../clangcompletion.h"
#include "../clangcompleter.h"
#include "../clangcodemodelplugin.h"
#include <cpptools/cppcompletionassist.h>
#include <texteditor/basetextdocument.h>
#include <texteditor/plaintexteditor.h>
#include <texteditor/codeassist/iassistproposal.h>
#include <texteditor/codeassist/iassistproposalmodel.h>
#include <texteditor/codeassist/basicproposalitemlistmodel.h>
#include <utils/fileutils.h>
#include <utils/changeset.h>
#include <QDir>
#include <QtTest>
using namespace ClangCodeModel;
using namespace ClangCodeModel::Internal;
using namespace TextEditor;
using namespace CPlusPlus;
using namespace CppTools::Internal;
namespace ClangCodeModel {
namespace Internal {
CompletionTestHelper::CompletionTestHelper(QObject *parent) :
QObject(parent),
m_completer(new ClangCompleter()),
m_position(m_line),
m_line(0),
m_column(0)
{
m_clangOptions << QLatin1String("-std=c++0x")
<< QLatin1String("-ObjC++");
}
CompletionTestHelper::~CompletionTestHelper()
{
}
void CompletionTestHelper::operator <<(const QString &fileName)
{
QResource res(QLatin1String(":/unittests/ClangCodeModel/") + fileName);
m_sourceCode = QByteArray(reinterpret_cast<const char*>(res.data()), res.size());
findCompletionPos();
QString path = QDir::tempPath() + QLatin1String("/file.h");
::Utils::FileSaver srcSaver(path);
srcSaver.write(m_sourceCode);
srcSaver.finalize();
m_completer->setFileName(path);
m_completer->setOptions(m_clangOptions);
}
QStringList CompletionTestHelper::codeCompleteTexts()
{
QList<CodeCompletionResult> results =
m_completer->codeCompleteAt(m_line, m_column, m_unsavedFiles);
QStringList completions;
foreach (const CodeCompletionResult& ccr, results)
completions << ccr.text();
return completions;
}
QList<CodeCompletionResult> CompletionTestHelper::codeComplete()
{
return m_completer->codeCompleteAt(m_line, m_column, m_unsavedFiles);
}
int CompletionTestHelper::position() const
{
return m_position;
}
const QByteArray &CompletionTestHelper::source() const
{
return m_sourceCode;
}
void CompletionTestHelper::addOption(const QString &option)
{
m_clangOptions << option;
}
void CompletionTestHelper::findCompletionPos()
{
m_position = m_sourceCode.indexOf("<<<<");
QVERIFY(m_position != -1);
m_sourceCode[m_position] = ' ';
m_sourceCode[m_position + 1] = ' ';
m_sourceCode[m_position + 2] = ' ';
m_sourceCode[m_position + 3] = ' ';
// substring from 0 to '@' position
QByteArray substr(m_sourceCode.data(), m_position);
m_line = 1;
m_column = 1;
for (int i = 0; i < substr.size(); ++i) {
if (substr[i] == '\n') {
++m_line;
m_column = 1;
} else {
++m_column;
}
}
}
} // namespace Internal
} // namespace ClangCodeModel
#endif

View File

@@ -0,0 +1,80 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef CLANGCODEMODEL_TESTS_COMPLETIONTESTHELPER_H
#define CLANGCODEMODEL_TESTS_COMPLETIONTESTHELPER_H
#ifdef WITH_TESTS
#include <QObject>
#include <QTextDocument>
#include <texteditor/basetexteditor.h>
#include <cplusplus/CppDocument.h>
#include <clangcompleter.h>
namespace TextEditor { class IAssistProposal; }
namespace ClangCodeModel {
namespace Internal {
class CompletionTestHelper : public QObject
{
Q_OBJECT
public:
explicit CompletionTestHelper(QObject *parent = 0);
~CompletionTestHelper();
void operator <<(const QString &fileName);
QStringList codeCompleteTexts();
QList<CodeCompletionResult> codeComplete();
int position() const;
const QByteArray &source() const;
void addOption(const QString &option);
private:
void findCompletionPos();
UnsavedFiles m_unsavedFiles;
ClangCompleter::Ptr m_completer;
QStringList m_clangOptions;
QByteArray m_sourceCode;
int m_position;
int m_line;
int m_column;
};
} // namespace Internal
} // namespace ClangCodeModel
#endif
#endif // CLANGCODEMODEL_TESTS_COMPLETIONTESTHELPER_H

View File

@@ -0,0 +1,44 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
/*
* Expected: 'sqr'
* Not expected: '~Math', 'operator='s
*/
class Math
{
int sqr(int a);
};
void foo()
{
Math math;
int sqr = math.<<<<;
}

View File

@@ -0,0 +1,50 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
/*
* Expected: 'i_first' 'c_first'
* Not expected: 'i_second' 'c_second' 'f_second'
*/
typedef struct {
int i_first;
char c_first;
} S1;
typedef struct {
int i_second;
char c_second;
float f_second;
} S2;
void foo()
{
S1 s;
s.<<<<;
}

View File

@@ -0,0 +1,68 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
/*
* Expected: 'i8' 'i64'
* Unexpected: 'Priv' 'operator='
*/
class Example
{
public:
Example();
~Example();
private:
class Priv;
Priv *d;
};
class Example::Priv
{
public:
int i8;
int i64;
Priv() : i8(8), i64(64) {}
};
Example::Example()
: d(new Example::Priv())
{
d-><<<<;
}
Example::~Example()
{
}
void f()
{
Example w;
}

View File

@@ -0,0 +1,41 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
/*
* Expected: 'action'
*/
void func()
{
struct impl
{
static void action() {}
};
impl::<<<<;
}

View File

@@ -0,0 +1,61 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
/*
* Expected: 'doB'
* Not expected: 'doA'
*/
struct A {
struct Inside {
void doA() {}
};
};
struct B {
struct Inside {
void doB() {}
};
};
template<class T> class C {
public:
typename T::Inside inner;
};
int main()
{
C<A> ca;
C<B> cb;
ca.inner.doA();
cb.inner.<<<<;
return 0;
}

View File

@@ -0,0 +1,50 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
/*
* Expected: 'OwningPtr'
*/
namespace llvm {
class OwningPtr;
}
namespace clang {
using llvm::OwningPtr;
}
class llvm::OwningPtr
{
};
void foo()
{
clang::<<<< ptr;
(void)ptr;
}

View File

@@ -0,0 +1,47 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
/*
* Expected: 'dataMember', 'anotherMember'
*/
class Data {
int dataMember;
};
template <class T> class Other : public T
{
int anotherMember;
};
void func()
{
Other<Data> c;
c.<<<<;
}

View File

@@ -0,0 +1,46 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
/*
* Expected: 'utils::'
* Not expected: 'utils'
*/
namespace utils
{
int sqr(int a)
{
return a * a;
}
}
void foo()
{
<<<<
}

View File

@@ -0,0 +1,54 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
/*
* Expected: 'EnumScoped::Value1', 'EnumScoped::Value2', 'EnumScoped::Value3'
* Unexpected: 'Value1'
*/
enum class EnumScoped
{
Value1,
Value2,
Value3
};
class ClassOwnsEnum
{
};
int main()
{
EnumScoped scoped = ;
switch (scoped) {
default:
break;
case <<<<
}
}

View File

@@ -0,0 +1,48 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
/*
Expected:
text 'reinterpret_cast<type>(expression)'
snippet 'reinterpret_cast<$type$>($expression$)'
text 'static_cast<type>(expression)'
snippet 'static_cast<$type$>($expression$)'
text 'new type(expressions)'
snippet 'new $type$($expressions$)'
*/
void foo()
{
int data[] = {
1, 2, 3
};
char *cdata = <<<<;
}

View File

@@ -0,0 +1,44 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
/*
Expected:
text 'private',
text 'protected',
text 'public',
text 'friend',
text 'virtual'
text 'typedef type name', snippet 'typedef $type$ $name$'
*/
class A
{
<<<<
};

View File

@@ -0,0 +1,52 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
// Expected:
// (List, List<$class Item$>),
// (Tuple, Tuple<$class First$, $class Second$, $typename Third$>)
template <class Item>
class List
{
Item *data;
};
template <class First, class Second, typename Third>
class Tuple
{
First *data;
Second *data2;
Third *data3;
};
void check()
{
<<<<
}

View File

@@ -0,0 +1,60 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
// Expected:
// (clamp, ),
// (perform, perform<$class T$>)
// (perform3, perform3<$class T$, $int E$, $class D$>)
// note: clang understands if parameter is redundant
template<class T>
T clamp(T value, T a = 0.0, T b = 1.0)
{
if (value < a)
return a;
if (value > b)
return b;
return value;
}
template<class T>
void perform()
{
}
template<class T, int E, class D>
void perform3()
{
}
void check()
{
<<<<
}

View File

@@ -0,0 +1,57 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
/*
* Expected texts:
* eatenAmount
* spectacleQuality:
* desiredAmountForDramaDose:andPersonsCount:
*
* Expected hints:
* -(int) eatenAmount
*
* -(int) spectacleQuality:(bool)unused
*/
@interface PopCornTracker {
int _quality;
int _eatenAmount;
int _remainedAmount;
}
+ (int) eatenAmount;
- (int) spectacleQuality : (bool)unused;
- (int) desiredAmountForDramaDose: (int)dose andPersonsCount: (int) count;
@end
@implementation PopCornTracker
- (int) desiredAmountForDramaDose: (int)dose andPersonsCount: (int) count
{
[self <<<<];
}
@end

View File

@@ -0,0 +1,42 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
@interface PopCornTracker {
int _quality;
int _eatenAmount;
int _remainedAmount;
}
+ (int) eatenAmount;
- (int) spectacleQuality;
+ (int) desiredAmountForDramaDose: (int)dose andPersonsCount: (int) count;
@end
@implementation PopCornTracker
+ <<<<
@end

View File

@@ -0,0 +1,54 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
@protocol Aaaa
@end
@interface Bbbb
@end
@interface PopCornTracker {
int _quality;
int _eatenAmount;
int _remainedAmount;
}
- (int) eatenAmount;
- (int) spectacleQuality;
- (int) desiredAmountForDramaDose: (int)dose andPersonsCount: (int) count;
+ (id) createNewTracker;
+ (id) createOldTracker:(Bbbb<Aaaa> *) aabb;
- (id) initWithOldTracker:(Bbbb<Aaaa> *) aabb;
@end
@interface AdvancedPopCornTracker : PopCornTracker {
}
- <<<<
@end

View File

@@ -0,0 +1,455 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "unit.h"
#include "unsavedfiledata.h"
#include "utils_p.h"
#include "raii/scopedclangoptions.h"
#include <clang-c/Index.h>
#include <QtCore/QByteArray>
#include <QtCore/QVector>
#include <QtCore/QSharedData>
#include <QtCore/QDateTime>
#include <QtAlgorithms>
#ifdef DEBUG_UNIT_COUNT
# include <QAtomicInt>
# include <QDebug>
static QBasicAtomicInt unitDataCount = Q_BASIC_ATOMIC_INITIALIZER(0);
#endif // DEBUG_UNIT_COUNT
namespace ClangCodeModel {
namespace Internal {
class UnitData : public QSharedData
{
public:
UnitData();
UnitData(const QString &fileName);
~UnitData();
void swap(UnitData *unitData);
void unload();
bool isLoaded() const;
void updateTimeStamp();
CXIndex m_index;
CXTranslationUnit m_tu;
QByteArray m_fileName;
QStringList m_compOptions;
SharedClangOptions m_sharedCompOptions;
unsigned m_managementOptions;
UnsavedFiles m_unsaved;
QDateTime m_timeStamp;
};
} // Internal
} // Clang
using namespace ClangCodeModel;
using namespace ClangCodeModel::Internal;
UnitData::UnitData()
: m_index(0)
, m_tu(0)
, m_managementOptions(0)
{
}
static const int DisplayDiagnostics = qgetenv("QTC_CLANG_VERBOSE").isEmpty() ? 0 : 1;
UnitData::UnitData(const QString &fileName)
: m_index(clang_createIndex(/*excludeDeclsFromPCH*/ 1, DisplayDiagnostics))
, m_tu(0)
, m_fileName(fileName.toUtf8())
, m_managementOptions(0)
{
}
UnitData::~UnitData()
{
unload();
clang_disposeIndex(m_index);
m_index = 0;
}
void UnitData::swap(UnitData *other)
{
qSwap(m_index, other->m_index);
qSwap(m_tu, other->m_tu);
qSwap(m_fileName, other->m_fileName);
qSwap(m_compOptions, other->m_compOptions);
qSwap(m_sharedCompOptions, other->m_sharedCompOptions);
qSwap(m_managementOptions, other->m_managementOptions);
qSwap(m_unsaved, other->m_unsaved);
qSwap(m_timeStamp, other->m_timeStamp);
}
void UnitData::unload()
{
if (m_tu) {
clang_disposeTranslationUnit(m_tu);
m_tu = 0;
#ifdef DEBUG_UNIT_COUNT
qDebug() << "# translation units:" << (unitDataCount.fetchAndAddOrdered(-1) - 1);
#endif // DEBUG_UNIT_COUNT
}
}
bool UnitData::isLoaded() const
{
return m_tu && m_index;
}
void UnitData::updateTimeStamp()
{
m_timeStamp = QDateTime::currentDateTime();
}
Unit::Unit()
: m_data(new UnitData)
{}
Unit::Unit(const QString &fileName)
: m_data(new UnitData(fileName))
{}
Unit::Unit(const Unit &unit)
: m_data(unit.m_data)
{}
Unit &Unit::operator =(const Unit &unit)
{
if (this != &unit)
m_data = unit.m_data;
return *this;
}
Unit::~Unit()
{}
const QString Unit::fileName() const
{
const QByteArray &name = m_data->m_fileName;
return QString::fromUtf8(name.data(), name.size());
}
bool Unit::isLoaded() const
{
return m_data->isLoaded();
}
const QDateTime &Unit::timeStamp() const
{
return m_data->m_timeStamp;
}
QStringList Unit::compilationOptions() const
{
return m_data->m_compOptions;
}
void Unit::setCompilationOptions(const QStringList &compOptions)
{
m_data->m_compOptions = compOptions;
m_data->m_sharedCompOptions.reloadOptions(compOptions);
}
UnsavedFiles Unit::unsavedFiles() const
{
return m_data->m_unsaved;
}
void Unit::setUnsavedFiles(const UnsavedFiles &unsavedFiles)
{
m_data->m_unsaved = unsavedFiles;
}
unsigned Unit::managementOptions() const
{
return m_data->m_managementOptions;
}
void Unit::setManagementOptions(unsigned managementOptions)
{
m_data->m_managementOptions = managementOptions;
}
bool Unit::isUnique() const
{
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
return m_data->ref.load() == 1;
#else
return m_data->ref == 1;
#endif
}
void Unit::makeUnique()
{
UnitData *uniqueData = new UnitData;
m_data->swap(uniqueData); // Notice we swap the data itself and not the shared pointer.
m_data = QExplicitlySharedDataPointer<UnitData>(uniqueData);
}
void Unit::parse()
{
m_data->unload();
m_data->updateTimeStamp();
UnsavedFileData unsaved(m_data->m_unsaved);
m_data->m_tu = clang_parseTranslationUnit(m_data->m_index,
m_data->m_fileName.constData(),
m_data->m_sharedCompOptions.data(),
m_data->m_sharedCompOptions.size(),
unsaved.files(),
unsaved.count(),
m_data->m_managementOptions);
}
void Unit::reparse()
{
Q_ASSERT(isLoaded());
UnsavedFileData unsaved(m_data->m_unsaved);
const unsigned opts = clang_defaultReparseOptions(m_data->m_tu);
if (clang_reparseTranslationUnit(m_data->m_tu, unsaved.count(), unsaved.files(), opts) != 0)
m_data->unload();
}
void Unit::create()
{
// @TODO
}
void Unit::createFromSourceFile()
{
// @TODO
}
int Unit::save(const QString &unitFileName)
{
Q_ASSERT(isLoaded());
return clang_saveTranslationUnit(m_data->m_tu,
unitFileName.toUtf8().constData(),
clang_defaultSaveOptions(m_data->m_tu));
}
void Unit::unload()
{
m_data->unload();
}
CXFile Unit::getFile() const
{
Q_ASSERT(isLoaded());
return clang_getFile(m_data->m_tu, m_data->m_fileName.constData());
}
CXCursor Unit::getCursor(const CXSourceLocation &location) const
{
Q_ASSERT(isLoaded());
return clang_getCursor(m_data->m_tu, location);
}
CXSourceLocation Unit::getLocation(const CXFile &file, unsigned line, unsigned column) const
{
Q_ASSERT(isLoaded());
return clang_getLocation(m_data->m_tu, file, line, column);
}
void Unit::codeCompleteAt(unsigned line, unsigned column, ScopedCXCodeCompleteResults &results)
{
unsigned flags = clang_defaultCodeCompleteOptions();
#if defined(CINDEX_VERSION) && (CINDEX_VERSION > 5)
flags |= CXCodeComplete_IncludeBriefComments;
#endif
UnsavedFileData unsaved(m_data->m_unsaved);
results.reset(clang_codeCompleteAt(m_data->m_tu, m_data->m_fileName.constData(),
line, column,
unsaved.files(), unsaved.count(), flags));
}
void Unit::tokenize(CXSourceRange range, CXToken **tokens, unsigned *tokenCount) const
{
Q_ASSERT(isLoaded());
Q_ASSERT(tokens);
Q_ASSERT(tokenCount);
Q_ASSERT(!clang_Range_isNull(range));
clang_tokenize(m_data->m_tu, range, tokens, tokenCount);
}
void Unit::disposeTokens(CXToken *tokens, unsigned tokenCount) const
{
Q_ASSERT(isLoaded());
clang_disposeTokens(m_data->m_tu, tokens, tokenCount);
}
CXSourceRange Unit::getTokenExtent(const CXToken &token) const
{
Q_ASSERT(isLoaded());
return clang_getTokenExtent(m_data->m_tu, token);
}
void Unit::annotateTokens(CXToken *tokens, unsigned tokenCount, CXCursor *cursors) const
{
Q_ASSERT(isLoaded());
Q_ASSERT(tokens);
Q_ASSERT(cursors);
clang_annotateTokens(m_data->m_tu, tokens, tokenCount, cursors);
}
CXTranslationUnit Unit::clangTranslationUnit() const
{
Q_ASSERT(isLoaded());
return m_data->m_tu;
}
CXIndex Unit::clangIndex() const
{
Q_ASSERT(isLoaded());
return m_data->m_index;
}
QString Unit::getTokenSpelling(const CXToken &tok) const
{
Q_ASSERT(isLoaded());
return getQString(clang_getTokenSpelling(m_data->m_tu, tok));
}
CXCursor Unit::getTranslationUnitCursor() const
{
Q_ASSERT(isLoaded());
return clang_getTranslationUnitCursor(m_data->m_tu);
}
CXString Unit::getTranslationUnitSpelling() const
{
Q_ASSERT(isLoaded());
return clang_getTranslationUnitSpelling(m_data->m_tu);
}
void Unit::getInclusions(CXInclusionVisitor visitor, CXClientData clientData) const
{
Q_ASSERT(isLoaded());
clang_getInclusions(m_data->m_tu, visitor, clientData);
}
unsigned Unit::getNumDiagnostics() const
{
Q_ASSERT(isLoaded());
return clang_getNumDiagnostics(m_data->m_tu);
}
CXDiagnostic Unit::getDiagnostic(unsigned index) const
{
Q_ASSERT(isLoaded());
return clang_getDiagnostic(m_data->m_tu, index);
}
IdentifierTokens::IdentifierTokens(const Unit &unit, unsigned firstLine, unsigned lastLine)
: m_unit(unit)
, m_tokenCount(0)
, m_tokens(0)
, m_cursors(0)
, m_extents(0)
{
Q_ASSERT(unit.isLoaded());
// Calculate the range:
CXFile file = unit.getFile();
CXSourceLocation startLocation = unit.getLocation(file, firstLine, 1);
CXSourceLocation endLocation = unit.getLocation(file, lastLine, 1);
CXSourceRange range = clang_getRange(startLocation, endLocation);
// Retrieve all identifier tokens:
unit.tokenize(range, &m_tokens, &m_tokenCount);
if (m_tokenCount == 0)
return;
// Get the cursors for the tokens:
m_cursors = new CXCursor[m_tokenCount];
unit.annotateTokens(m_tokens,
m_tokenCount,
m_cursors);
m_extents = new CXSourceRange[m_tokenCount];
// Create the markers using the cursor to check the types:
for (unsigned i = 0; i < m_tokenCount; ++i)
m_extents[i] = unit.getTokenExtent(m_tokens[i]);
}
IdentifierTokens::~IdentifierTokens()
{
dispose();
}
void IdentifierTokens::dispose()
{
if (!m_unit.isLoaded())
return;
if (m_tokenCount && m_tokens) {
m_unit.disposeTokens(m_tokens, m_tokenCount);
m_tokens = 0;
m_tokenCount = 0;
}
if (m_cursors) {
delete[] m_cursors;
m_cursors = 0;
}
if (m_extents) {
delete[] m_extents;
m_extents = 0;
}
}

View File

@@ -0,0 +1,195 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef UNIT_H
#define UNIT_H
#include "utils.h"
#include "cxraii.h"
#include <QExplicitlySharedDataPointer>
#include <QMetaType>
#include <QString>
#include <QStringList>
#include <QVarLengthArray>
QT_BEGIN_NAMESPACE
class QDateTime;
QT_END_NAMESPACE
namespace ClangCodeModel {
namespace Internal {
class UnitData;
/*
* This is a minimal wrapper around clang's translation unit functionality.
* It should should contain only the very basic primitives which allow other
* components such as code completion, code navigation, and others to access
* data which directly depends on the translation unit.
*
* In other words, what's wrapped here is only the functions that receive a
* CXTranslationUnit as a parameter. And this class itself is then the corresponding
* abstraction of the CXTranslationUnit.
*
* Notes:
* - This class is not thread-safe.
* - It's responsibility of the client to make sure that the wrapped translation
* unit is consistent with the other data such as cursor and locations being used.
* - The data of the TU is shared.
*
*
* @TODO: This is similar but not exactly the same as the current ClangWrapper class.
* That class is now tuned to specific features, so it's not generic enough to be used
* an underlying component and aslo don't provide the data in a fine granularity as
* needed here. At some point we should split ClangWrapper into its different logical
* components and use this is the underlying structure.
*/
class Unit
{
public:
Unit();
explicit Unit(const QString &fileName);
Unit(const Unit &unit);
Unit &operator=(const Unit &unit);
~Unit();
bool isLoaded() const;
const QString fileName() const;
const QDateTime &timeStamp() const;
QStringList compilationOptions() const;
void setCompilationOptions(const QStringList &compOptions);
UnsavedFiles unsavedFiles() const;
void setUnsavedFiles(const UnsavedFiles &unsavedFiles);
unsigned managementOptions() const;
void setManagementOptions(unsigned managementOptions);
// Sharing control facilities
// Method isUnique is just like an "isDetached", however makeUnique is mostly some kind
// of "detach" but which actually moves the data to this particular instance, invalidating
// then all the other shares.
bool isUnique() const;
void makeUnique();
// Methods for generating the TU. Name mappings are direct, for example:
// - parse corresponds to clang_parseTranslationUnit
// - createFromSourceFile corresponds to clang_createTranslationUnitFromSourceFile
void parse();
void reparse();
void create();
void createFromSourceFile();
int save(const QString &unitFileName);
void unload();
// Simple forwarding methods, separated by clang categories for convenience.
// As above, the names are directly mapped. Separated by categories as clang for convenience.
// Note that only methods that take the TU as a parameter should be wrapped.
// - Diagnostic reporting
unsigned getNumDiagnostics() const;
CXDiagnostic getDiagnostic(unsigned index) const;
// - Translation unit manipulation
CXString getTranslationUnitSpelling() const;
// - File manipulation routines
CXFile getFile() const;
// - Mapping between cursors and source code
CXCursor getCursor(const CXSourceLocation &location) const;
// - Miscellaneous utility functions
void getInclusions(CXInclusionVisitor visitor, CXClientData clientData) const;
// - Cursor manipulations
CXCursor getTranslationUnitCursor() const;
// - Physical source locations
CXSourceLocation getLocation(const CXFile &file, unsigned line, unsigned column) const;
void codeCompleteAt(unsigned line, unsigned column, ScopedCXCodeCompleteResults &results);
void tokenize(CXSourceRange range, CXToken **tokens, unsigned *tokenCount) const;
void disposeTokens(CXToken *tokens, unsigned tokenCount) const;
CXSourceRange getTokenExtent(const CXToken &token) const;
void annotateTokens(CXToken *tokens, unsigned tokenCount, CXCursor *cursors) const;
CXTranslationUnit clangTranslationUnit() const;
CXIndex clangIndex() const;
QString getTokenSpelling(const CXToken &tok) const;
private:
QExplicitlySharedDataPointer<UnitData> m_data;
};
class IdentifierTokens
{
Q_DISABLE_COPY(IdentifierTokens)
public:
IdentifierTokens(const Unit &m_unit, unsigned firstLine, unsigned lastLine);
~IdentifierTokens();
unsigned count() const
{ return m_tokenCount; }
const CXToken &token(unsigned nr) const
{ Q_ASSERT(nr < count()); return m_tokens[nr]; }
const CXCursor &cursor(unsigned nr) const
{ Q_ASSERT(nr < count()); return m_cursors[nr]; }
const CXSourceRange &extent(unsigned nr) const
{ Q_ASSERT(nr < count()); return m_extents[nr]; }
private:
void dispose();
private:
const Unit &m_unit;
unsigned m_tokenCount;
CXToken *m_tokens;
CXCursor *m_cursors;
CXSourceRange *m_extents;
};
} // Internal
} // Clang
Q_DECLARE_METATYPE(ClangCodeModel::Internal::Unit)
#endif // UNIT_H

View File

@@ -0,0 +1,61 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "unsavedfiledata.h"
using namespace ClangCodeModel::Internal;
UnsavedFileData::UnsavedFileData(const UnsavedFiles &unsavedFiles)
: m_count(unsavedFiles.count())
, m_files(0)
{
if (m_count) {
m_files = new CXUnsavedFile[m_count];
unsigned idx = 0;
for (UnsavedFiles::const_iterator it = unsavedFiles.begin(); it != unsavedFiles.end(); ++it, ++idx) {
QByteArray contents = it.value();
const char *contentChars = qstrdup(contents.constData());
m_files[idx].Contents = contentChars;
m_files[idx].Length = contents.size();
const char *fileName = qstrdup(it.key().toUtf8().constData());
m_files[idx].Filename = fileName;
}
}
}
UnsavedFileData::~UnsavedFileData()
{
for (unsigned i = 0; i < m_count; ++i) {
delete[] m_files[i].Contents;
delete[] m_files[i].Filename;
}
delete[] m_files;
}

View File

@@ -0,0 +1,65 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef CLANG_INTERNAL_UNSAVEDFILEDATA_H
#define CLANG_INTERNAL_UNSAVEDFILEDATA_H
#include "utils.h"
#include <clang-c/Index.h>
namespace ClangCodeModel {
namespace Internal {
class UnsavedFileData
{
UnsavedFileData(const UnsavedFileData &);
UnsavedFileData &operator=(const UnsavedFileData &);
typedef ClangCodeModel::Internal::UnsavedFiles UnsavedFiles;
public:
UnsavedFileData(const UnsavedFiles &unsavedFiles);
~UnsavedFileData();
unsigned count() const
{ return m_count; }
CXUnsavedFile *files() const
{ return m_files; }
private:
unsigned m_count;
CXUnsavedFile *m_files;
};
} // namespace Internal
} // namespace ClangCodeModel
#endif // CLANG_INTERNAL_UNSAVEDFILEDATA_H

View File

@@ -0,0 +1,89 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "diagnostic.h"
#include "unit.h"
#include "utils.h"
#include "utils_p.h"
#include <clang-c/Index.h>
#include <QMutex>
#include <QMutexLocker>
namespace ClangCodeModel {
namespace Internal {
QPair<bool, QStringList> precompile(const PchInfo::Ptr &pchInfo)
{
// qDebug() << "*** Precompiling" << pchInfo->inputFileName()
// << "into" << pchInfo->fileName()
// << "with options" << pchInfo->options();
bool ok = false;
Internal::Unit unit(pchInfo->inputFileName());
unit.setCompilationOptions(pchInfo->options());
unsigned parseOpts = CXTranslationUnit_ForSerialization
| CXTranslationUnit_Incomplete;
unit.setManagementOptions(parseOpts);
unit.parse();
if (unit.isLoaded())
ok = CXSaveError_None == unit.save(pchInfo->fileName());
return qMakePair(ok, Internal::formattedDiagnostics(unit));
}
namespace {
static bool clangInitialised = false;
static QMutex initialisationMutex;
} // anonymous namespace
void initializeClang()
{
if (clangInitialised)
return;
QMutexLocker locker(&initialisationMutex);
if (clangInitialised)
return;
clang_toggleCrashRecovery(1);
clang_enableStackTraces();
clangInitialised = true;
qRegisterMetaType<ClangCodeModel::Diagnostic>();
qRegisterMetaType<QList<ClangCodeModel::Diagnostic> >();
}
} // Internal namespace
} // ClangCodeModel namespace

View File

@@ -0,0 +1,65 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef UTILS_H
#define UTILS_H
#include "pchinfo.h"
#include <QString>
#include <QStringList>
#include <QByteArray>
#include <QMap>
#include <QPair>
/*
* A header for globally visible typedefs. This is particularly useful
* so we don't have to #include files simply because of a typedef. Still,
* not every typedef should go in here, only the minimal subset of the
* ones which are needed quite often.
*/
namespace ClangCodeModel {
namespace Internal {
typedef QMap<QString, QByteArray> UnsavedFiles;
/**
* Utility method to create a PCH file from a header file.
*
* \returns a boolean indicating success (true) or failure (false), and a
* list of diagnostic messages.
*/
QPair<bool, QStringList> precompile(const PchInfo::Ptr &pchInfo);
void initializeClang();
} // Internal namespace
} // ClangCodeModel namespace
#endif // UTILS_H

View File

@@ -0,0 +1,124 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "unit.h"
#include "utils_p.h"
#include <QtCore/QDir>
#include <QtCore/QFileInfo>
namespace ClangCodeModel {
namespace Internal {
QString getQString(const CXString &cxString, bool disposeCXString)
{
QString s = QString::fromUtf8(clang_getCString(cxString));
if (disposeCXString)
clang_disposeString(cxString);
return s;
}
namespace {
SourceLocation getLocation(const CXSourceLocation &loc,
void (*clangFunction)(CXSourceLocation,
CXFile *,
unsigned *,
unsigned *,
unsigned *))
{
CXFile file;
unsigned line, column, offset;
(*clangFunction)(loc, &file, &line, &column, &offset);
return SourceLocation(normalizeFileName(getQString(clang_getFileName(file))),
line,
column,
offset);
}
} // Anonymous
SourceLocation getInstantiationLocation(const CXSourceLocation &loc)
{
return getLocation(loc, &clang_getInstantiationLocation);
}
SourceLocation getSpellingLocation(const CXSourceLocation &loc)
{
return getLocation(loc, &clang_getSpellingLocation);
}
SourceLocation getExpansionLocation(const CXSourceLocation &loc)
{
// return getLocation(loc, &clang_getExpansionLocation);
return getLocation(loc, &clang_getInstantiationLocation);
}
QString normalizeFileName(const QString &fileName)
{
if (fileName.isEmpty())
return fileName;
return normalizeFileName(QFileInfo(fileName));
}
QString normalizeFileName(const QFileInfo &fileInfo)
{
if (!fileInfo.isFile())
return QString();
return QDir::cleanPath(fileInfo.absoluteFilePath());
}
QStringList formattedDiagnostics(const Unit &unit)
{
QStringList diags;
if (!unit.isLoaded())
return diags;
const unsigned count = unit.getNumDiagnostics();
for (unsigned i = 0; i < count; ++i) {
CXDiagnostic diag = unit.getDiagnostic(i);
unsigned opt = CXDiagnostic_DisplaySourceLocation
| CXDiagnostic_DisplayColumn
| CXDiagnostic_DisplaySourceRanges
| CXDiagnostic_DisplayOption
| CXDiagnostic_DisplayCategoryId
| CXDiagnostic_DisplayCategoryName
;
diags << getQString(clang_formatDiagnostic(diag, opt));
clang_disposeDiagnostic(diag);
}
return diags;
}
} // Internal
} // ClangCodeModel

View File

@@ -0,0 +1,66 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef CLANG_REUSE_H
#define CLANG_REUSE_H
#include "sourcelocation.h"
#include <clang-c/Index.h>
#include <QtCore/QString>
QT_BEGIN_NAMESPACE
class QFileInfo;
QT_END_NAMESPACE
namespace ClangCodeModel {
namespace Internal {
class Unit;
QString getQString(const CXString &cxString, bool disposeCXString = true);
SourceLocation getInstantiatonLocation(const CXSourceLocation &loc); // Deprecated
SourceLocation getSpellingLocation(const CXSourceLocation &loc);
SourceLocation getExpansionLocation(const CXSourceLocation &loc);
// There are slight differences of behavior from apparently similar Qt file processing functions.
// For instance, QFileInfo::absoluteFilePath will uppercase driver letters, while the corresponding
// QDir function will not do so. Besides, we need to keep paths clean. So in order to avoid
// inconsistencies the functions below should be used for any indexing related task.
QString normalizeFileName(const QString &fileName);
QString normalizeFileName(const QFileInfo &fileInfo);
QStringList formattedDiagnostics(const Unit &unit);
} // Internal
} // ClangCodeModel
#endif // CLANG_REUSE_H

View File

@@ -1565,6 +1565,8 @@ void CPPEditorWidget::setFontSettings(const TextEditor::FontSettings &fs)
fs.toTextCharFormat(TextEditor::C_FUNCTION);
m_semanticHighlightFormatMap[CppHighlightingSupport::PseudoKeywordUse] =
fs.toTextCharFormat(TextEditor::C_KEYWORD);
m_semanticHighlightFormatMap[CppHighlightingSupport::StringUse] =
fs.toTextCharFormat(TextEditor::C_STRING);
m_keywordFormat = fs.toTextCharFormat(TextEditor::C_KEYWORD);
// only set the background, we do not want to modify foreground properties

View File

@@ -42,6 +42,17 @@
namespace CppTools {
#ifdef _MSC_VER
// Short explanation: QFutureInterface is currently used as a base for an exported class
// (see CreateMarkers). Even though it's not explicitly marked to be exported VC++ will
// implicitly export it (more details on the General Rules and Limitations of dllexport/
// dllimport MSDN page). When seen here as a base of CheckSymbols the compiler tries to
// instantiate this template (since the declaration of template doesn't have any explicit
// export/import attribute) which will eventually collide with the already defined symbol.
// The line below simply tells the compiler to import the template instead of instantiating.
template class Q_DECL_IMPORT QFutureInterface<CppEditor::Internal::SemanticInfo::Use>;
#endif
class CPPTOOLS_EXPORT CheckSymbols:
protected CPlusPlus::ASTVisitor,
public QRunnable,

View File

@@ -44,7 +44,7 @@ CppCodeModelSettingsWidget::CppCodeModelSettingsWidget(QWidget *parent)
{
m_ui->setupUi(this);
m_ui->theGroupBox->setVisible(false);
m_ui->theGroupBox->setVisible(true);
}
CppCodeModelSettingsWidget::~CppCodeModelSettingsWidget()

View File

@@ -57,7 +57,8 @@ public:
LabelUse,
MacroUse,
FunctionUse,
PseudoKeywordUse
PseudoKeywordUse,
StringUse
};
public:

View File

@@ -50,6 +50,12 @@ SUBDIRS = \
baremetal \
ios
# prefer qmake variable set on command line over env var
isEmpty(LLVM_INSTALL_DIR):LLVM_INSTALL_DIR=$$(LLVM_INSTALL_DIR)
!isEmpty(LLVM_INSTALL_DIR) {
SUBDIRS += clangcodemodel
}
isEmpty(QBS_INSTALL_DIR): QBS_INSTALL_DIR = $$(QBS_INSTALL_DIR)
exists(../shared/qbs/qbs.pro)|!isEmpty(QBS_INSTALL_DIR): \
SUBDIRS += \