Commit 5beb74fd authored by Erik Verbruggen's avatar Erik Verbruggen Committed by hjk

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: default avatarhjk <hjk121@nokiamail.com>
parent 93b75284
/****************************************************************************
**
** 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
......@@ -38,7 +38,8 @@ DATA_DIRS = \
qml \
qml-type-descriptions \
generic-highlighter \
glsl
glsl \
cplusplus
macx: DATA_DIRS += scripts
for(data_dir, DATA_DIRS) {
......
<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>
/****************************************************************************
**
** 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
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}
}
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
}
QTC_PLUGIN_NAME = ClangCodeModel
QTC_LIB_DEPENDS += \
utils
QTC_PLUGIN_DEPENDS += \
coreplugin \
cpptools \
texteditor
/****************************************************************************
**
** 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)
/****************************************************************************
**
** 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
/****************************************************************************
**
** 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
{