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,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;
}