2015-06-01 18:51:55 +02:00
|
|
|
/****************************************************************************
|
|
|
|
|
**
|
2016-01-15 14:57:14 +01:00
|
|
|
** Copyright (C) 2016 The Qt Company Ltd.
|
|
|
|
|
** Contact: https://www.qt.io/licensing/
|
2015-06-01 18:51:55 +02:00
|
|
|
**
|
|
|
|
|
** This file is part of Qt Creator.
|
|
|
|
|
**
|
|
|
|
|
** Commercial License Usage
|
|
|
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
|
|
|
** accordance with the commercial license agreement provided with the
|
|
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
2016-01-15 14:57:14 +01:00
|
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
|
|
|
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
|
|
|
** information use the contact form at https://www.qt.io/contact-us.
|
2015-06-01 18:51:55 +02:00
|
|
|
**
|
2016-01-15 14:57:14 +01:00
|
|
|
** GNU General Public License Usage
|
|
|
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
|
|
|
** General Public License version 3 as published by the Free Software
|
|
|
|
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
|
|
|
|
** included in the packaging of this file. Please review the following
|
|
|
|
|
** information to ensure the GNU General Public License requirements will
|
|
|
|
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
2015-06-01 18:51:55 +02:00
|
|
|
**
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
|
|
#include "codecompletionsextractor.h"
|
|
|
|
|
|
|
|
|
|
#include "clangstring.h"
|
|
|
|
|
#include "codecompletionchunkconverter.h"
|
|
|
|
|
|
|
|
|
|
#include <QDebug>
|
|
|
|
|
|
2015-06-16 11:56:00 +02:00
|
|
|
namespace ClangBackEnd {
|
2015-06-01 18:51:55 +02:00
|
|
|
|
|
|
|
|
CodeCompletionsExtractor::CodeCompletionsExtractor(CXCodeCompleteResults *cxCodeCompleteResults)
|
|
|
|
|
: cxCodeCompleteResults(cxCodeCompleteResults)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CodeCompletionsExtractor::next()
|
|
|
|
|
{
|
|
|
|
|
const uint cxCodeCompleteResultCount = cxCodeCompleteResults->NumResults;
|
|
|
|
|
|
|
|
|
|
++cxCodeCompleteResultIndex;
|
|
|
|
|
|
|
|
|
|
if (cxCodeCompleteResultIndex < cxCodeCompleteResultCount) {
|
|
|
|
|
currentCxCodeCompleteResult = cxCodeCompleteResults->Results[cxCodeCompleteResultIndex];
|
|
|
|
|
|
|
|
|
|
currentCodeCompletion_ = CodeCompletion();
|
|
|
|
|
|
|
|
|
|
extractCompletionKind();
|
|
|
|
|
extractText();
|
|
|
|
|
extractPriority();
|
|
|
|
|
extractAvailability();
|
|
|
|
|
extractHasParameters();
|
2015-08-25 16:19:19 +02:00
|
|
|
extractBriefComment();
|
2015-06-01 18:51:55 +02:00
|
|
|
extractCompletionChunks();
|
2015-07-07 13:09:04 +02:00
|
|
|
adaptPriority();
|
2015-06-01 18:51:55 +02:00
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CodeCompletionsExtractor::peek(const Utf8String &name)
|
|
|
|
|
{
|
|
|
|
|
const uint cxCodeCompleteResultCount = cxCodeCompleteResults->NumResults;
|
|
|
|
|
|
|
|
|
|
uint peekCxCodeCompleteResultIndex = cxCodeCompleteResultIndex + 1;
|
|
|
|
|
|
|
|
|
|
while (peekCxCodeCompleteResultIndex < cxCodeCompleteResultCount) {
|
|
|
|
|
if (hasText(name, cxCodeCompleteResults->Results[peekCxCodeCompleteResultIndex].CompletionString))
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
++peekCxCodeCompleteResultIndex;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-22 17:33:27 +02:00
|
|
|
CodeCompletions CodeCompletionsExtractor::extractAll()
|
2015-06-01 18:51:55 +02:00
|
|
|
{
|
2015-07-22 17:33:27 +02:00
|
|
|
CodeCompletions codeCompletions;
|
2017-06-20 11:38:32 +02:00
|
|
|
codeCompletions.reserve(int(cxCodeCompleteResults->NumResults));
|
2015-06-01 18:51:55 +02:00
|
|
|
|
|
|
|
|
while (next())
|
|
|
|
|
codeCompletions.append(currentCodeCompletion_);
|
|
|
|
|
|
|
|
|
|
return codeCompletions;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CodeCompletionsExtractor::extractCompletionKind()
|
|
|
|
|
{
|
|
|
|
|
switch (currentCxCodeCompleteResult.CursorKind) {
|
|
|
|
|
case CXCursor_FunctionTemplate:
|
|
|
|
|
currentCodeCompletion_.setCompletionKind(CodeCompletion::TemplateFunctionCompletionKind);
|
|
|
|
|
break;
|
|
|
|
|
case CXCursor_CXXMethod:
|
|
|
|
|
extractMethodCompletionKind();
|
|
|
|
|
break;
|
|
|
|
|
case CXCursor_FunctionDecl:
|
2015-07-15 17:38:46 +02:00
|
|
|
case CXCursor_ConversionFunction:
|
2015-06-01 18:51:55 +02:00
|
|
|
currentCodeCompletion_.setCompletionKind(CodeCompletion::FunctionCompletionKind);
|
|
|
|
|
break;
|
|
|
|
|
case CXCursor_VariableRef:
|
|
|
|
|
case CXCursor_VarDecl:
|
|
|
|
|
case CXCursor_FieldDecl:
|
|
|
|
|
case CXCursor_ParmDecl:
|
|
|
|
|
case CXCursor_NonTypeTemplateParameter:
|
|
|
|
|
currentCodeCompletion_.setCompletionKind(CodeCompletion::VariableCompletionKind);
|
|
|
|
|
break;
|
|
|
|
|
case CXCursor_StructDecl:
|
|
|
|
|
case CXCursor_UnionDecl:
|
|
|
|
|
case CXCursor_ClassDecl:
|
|
|
|
|
case CXCursor_TemplateTypeParameter:
|
|
|
|
|
currentCodeCompletion_.setCompletionKind(CodeCompletion::ClassCompletionKind);
|
|
|
|
|
break;
|
2015-12-08 13:01:25 +01:00
|
|
|
case CXCursor_TypedefDecl:
|
|
|
|
|
case CXCursor_TypeAliasDecl:
|
|
|
|
|
currentCodeCompletion_.setCompletionKind(CodeCompletion::TypeAliasCompletionKind);
|
|
|
|
|
break;
|
2015-06-01 18:51:55 +02:00
|
|
|
case CXCursor_ClassTemplatePartialSpecialization:
|
|
|
|
|
case CXCursor_ClassTemplate:
|
|
|
|
|
case CXCursor_TemplateTemplateParameter:
|
|
|
|
|
currentCodeCompletion_.setCompletionKind(CodeCompletion::TemplateClassCompletionKind);
|
|
|
|
|
break;
|
|
|
|
|
case CXCursor_Namespace:
|
|
|
|
|
case CXCursor_NamespaceAlias:
|
|
|
|
|
currentCodeCompletion_.setCompletionKind(CodeCompletion::NamespaceCompletionKind);
|
|
|
|
|
break;
|
|
|
|
|
case CXCursor_EnumDecl:
|
|
|
|
|
currentCodeCompletion_.setCompletionKind(CodeCompletion::EnumerationCompletionKind);
|
|
|
|
|
break;
|
|
|
|
|
case CXCursor_EnumConstantDecl:
|
|
|
|
|
currentCodeCompletion_.setCompletionKind(CodeCompletion::EnumeratorCompletionKind);
|
|
|
|
|
break;
|
|
|
|
|
case CXCursor_Constructor:
|
|
|
|
|
currentCodeCompletion_.setCompletionKind(CodeCompletion::ConstructorCompletionKind);
|
|
|
|
|
break;
|
|
|
|
|
case CXCursor_Destructor:
|
|
|
|
|
currentCodeCompletion_.setCompletionKind(CodeCompletion::DestructorCompletionKind);
|
|
|
|
|
break;
|
|
|
|
|
case CXCursor_MacroDefinition:
|
|
|
|
|
extractMacroCompletionKind();
|
|
|
|
|
break;
|
|
|
|
|
case CXCursor_NotImplemented:
|
|
|
|
|
currentCodeCompletion_.setCompletionKind(CodeCompletion::KeywordCompletionKind);
|
|
|
|
|
break;
|
2017-04-28 17:46:40 +02:00
|
|
|
case CXCursor_OverloadCandidate:
|
|
|
|
|
currentCodeCompletion_.setCompletionKind(CodeCompletion::FunctionOverloadCompletionKind);
|
|
|
|
|
break;
|
2015-06-01 18:51:55 +02:00
|
|
|
default:
|
|
|
|
|
currentCodeCompletion_.setCompletionKind(CodeCompletion::Other);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CodeCompletionsExtractor::extractText()
|
|
|
|
|
{
|
|
|
|
|
const uint completionChunkCount = clang_getNumCompletionChunks(currentCxCodeCompleteResult.CompletionString);
|
|
|
|
|
for (uint chunkIndex = 0; chunkIndex < completionChunkCount; ++chunkIndex) {
|
|
|
|
|
const CXCompletionChunkKind chunkKind = clang_getCompletionChunkKind(currentCxCodeCompleteResult.CompletionString, chunkIndex);
|
|
|
|
|
if (chunkKind == CXCompletionChunk_TypedText) {
|
|
|
|
|
currentCodeCompletion_.setText(CodeCompletionChunkConverter::chunkText(currentCxCodeCompleteResult.CompletionString, chunkIndex));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CodeCompletionsExtractor::extractMethodCompletionKind()
|
|
|
|
|
{
|
|
|
|
|
CXCompletionString cxCompletionString = cxCodeCompleteResults->Results[cxCodeCompleteResultIndex].CompletionString;
|
|
|
|
|
const uint annotationCount = clang_getCompletionNumAnnotations(cxCompletionString);
|
|
|
|
|
|
|
|
|
|
for (uint annotationIndex = 0; annotationIndex < annotationCount; ++annotationIndex) {
|
|
|
|
|
ClangString annotation = clang_getCompletionAnnotation(cxCompletionString, annotationIndex);
|
|
|
|
|
|
|
|
|
|
if (annotation == Utf8StringLiteral("qt_signal")) {
|
|
|
|
|
currentCodeCompletion_.setCompletionKind(CodeCompletion::SignalCompletionKind);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (annotation == Utf8StringLiteral("qt_slot")) {
|
|
|
|
|
currentCodeCompletion_.setCompletionKind(CodeCompletion::SlotCompletionKind);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
currentCodeCompletion_.setCompletionKind(CodeCompletion::FunctionCompletionKind);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CodeCompletionsExtractor::extractMacroCompletionKind()
|
|
|
|
|
{
|
|
|
|
|
CXCompletionString cxCompletionString = cxCodeCompleteResults->Results[cxCodeCompleteResultIndex].CompletionString;
|
|
|
|
|
|
|
|
|
|
const uint completionChunkCount = clang_getNumCompletionChunks(cxCompletionString);
|
|
|
|
|
|
|
|
|
|
for (uint chunkIndex = 0; chunkIndex < completionChunkCount; ++chunkIndex) {
|
|
|
|
|
CXCompletionChunkKind kind = clang_getCompletionChunkKind(cxCompletionString, chunkIndex);
|
|
|
|
|
if (kind == CXCompletionChunk_Placeholder) {
|
|
|
|
|
currentCodeCompletion_.setCompletionKind(CodeCompletion::FunctionCompletionKind);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
currentCodeCompletion_.setCompletionKind(CodeCompletion::PreProcessorCompletionKind);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CodeCompletionsExtractor::extractPriority()
|
|
|
|
|
{
|
|
|
|
|
CXCompletionString cxCompletionString = cxCodeCompleteResults->Results[cxCodeCompleteResultIndex].CompletionString;
|
|
|
|
|
quint32 priority = clang_getCompletionPriority(cxCompletionString);
|
|
|
|
|
currentCodeCompletion_.setPriority(priority);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CodeCompletionsExtractor::extractAvailability()
|
|
|
|
|
{
|
|
|
|
|
CXCompletionString cxCompletionString = cxCodeCompleteResults->Results[cxCodeCompleteResultIndex].CompletionString;
|
|
|
|
|
CXAvailabilityKind cxAvailabilityKind = clang_getCompletionAvailability(cxCompletionString);
|
|
|
|
|
|
|
|
|
|
switch (cxAvailabilityKind) {
|
|
|
|
|
case CXAvailability_Available:
|
|
|
|
|
currentCodeCompletion_.setAvailability(CodeCompletion::Available);
|
|
|
|
|
break;
|
|
|
|
|
case CXAvailability_Deprecated:
|
|
|
|
|
currentCodeCompletion_.setAvailability(CodeCompletion::Deprecated);
|
|
|
|
|
break;
|
|
|
|
|
case CXAvailability_NotAvailable:
|
|
|
|
|
currentCodeCompletion_.setAvailability(CodeCompletion::NotAvailable);
|
|
|
|
|
break;
|
|
|
|
|
case CXAvailability_NotAccessible:
|
|
|
|
|
currentCodeCompletion_.setAvailability(CodeCompletion::NotAccessible);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CodeCompletionsExtractor::extractHasParameters()
|
|
|
|
|
{
|
|
|
|
|
const uint completionChunkCount = clang_getNumCompletionChunks(currentCxCodeCompleteResult.CompletionString);
|
|
|
|
|
for (uint chunkIndex = 0; chunkIndex < completionChunkCount; ++chunkIndex) {
|
|
|
|
|
const CXCompletionChunkKind chunkKind = clang_getCompletionChunkKind(currentCxCodeCompleteResult.CompletionString, chunkIndex);
|
|
|
|
|
if (chunkKind == CXCompletionChunk_LeftParen) {
|
|
|
|
|
const CXCompletionChunkKind nextChunkKind = clang_getCompletionChunkKind(currentCxCodeCompleteResult.CompletionString, chunkIndex + 1);
|
|
|
|
|
currentCodeCompletion_.setHasParameters(nextChunkKind != CXCompletionChunk_RightParen);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-25 16:19:19 +02:00
|
|
|
void CodeCompletionsExtractor::extractBriefComment()
|
|
|
|
|
{
|
|
|
|
|
ClangString briefComment = clang_getCompletionBriefComment(currentCxCodeCompleteResult.CompletionString);
|
|
|
|
|
|
|
|
|
|
currentCodeCompletion_.setBriefComment(briefComment);
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-01 18:51:55 +02:00
|
|
|
void CodeCompletionsExtractor::extractCompletionChunks()
|
|
|
|
|
{
|
|
|
|
|
currentCodeCompletion_.setChunks(CodeCompletionChunkConverter::extract(currentCxCodeCompleteResult.CompletionString));
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-07 13:09:04 +02:00
|
|
|
void CodeCompletionsExtractor::adaptPriority()
|
|
|
|
|
{
|
|
|
|
|
decreasePriorityForDestructors();
|
|
|
|
|
decreasePriorityForNonAvailableCompletions();
|
|
|
|
|
decreasePriorityForQObjectInternals();
|
|
|
|
|
decreasePriorityForSignals();
|
2015-07-15 17:38:46 +02:00
|
|
|
decreasePriorityForOperators();
|
2015-07-07 13:09:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CodeCompletionsExtractor::decreasePriorityForNonAvailableCompletions()
|
|
|
|
|
{
|
|
|
|
|
if (currentCodeCompletion_.availability() != CodeCompletion::Available)
|
|
|
|
|
currentCodeCompletion_.setPriority(currentCodeCompletion_.priority() * 100);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CodeCompletionsExtractor::decreasePriorityForDestructors()
|
|
|
|
|
{
|
|
|
|
|
if (currentCodeCompletion_.completionKind() == CodeCompletion::DestructorCompletionKind)
|
|
|
|
|
currentCodeCompletion_.setPriority(currentCodeCompletion_.priority() * 100);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CodeCompletionsExtractor::decreasePriorityForSignals()
|
|
|
|
|
{
|
|
|
|
|
if (currentCodeCompletion_.completionKind() == CodeCompletion::SignalCompletionKind)
|
|
|
|
|
currentCodeCompletion_.setPriority(currentCodeCompletion_.priority() * 100);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CodeCompletionsExtractor::decreasePriorityForQObjectInternals()
|
|
|
|
|
{
|
|
|
|
|
quint32 priority = currentCodeCompletion_.priority();
|
|
|
|
|
|
|
|
|
|
if (currentCodeCompletion_.text().startsWith("qt_"))
|
|
|
|
|
priority *= 100;
|
|
|
|
|
|
|
|
|
|
if (currentCodeCompletion_.text() == Utf8StringLiteral("metaObject"))
|
|
|
|
|
priority *= 10;
|
|
|
|
|
|
|
|
|
|
if (currentCodeCompletion_.text() == Utf8StringLiteral("staticMetaObject"))
|
|
|
|
|
priority *= 100;
|
|
|
|
|
|
|
|
|
|
currentCodeCompletion_.setPriority(priority);
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-15 17:38:46 +02:00
|
|
|
bool isOperator(CXCursorKind cxCursorKind, const Utf8String &name)
|
|
|
|
|
{
|
|
|
|
|
return cxCursorKind == CXCursor_ConversionFunction
|
|
|
|
|
|| (cxCursorKind == CXCursor_CXXMethod
|
|
|
|
|
&& name.startsWith(Utf8StringLiteral("operator")));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CodeCompletionsExtractor::decreasePriorityForOperators()
|
|
|
|
|
{
|
|
|
|
|
quint32 priority = currentCodeCompletion_.priority();
|
|
|
|
|
|
|
|
|
|
if (isOperator(currentCxCodeCompleteResult.CursorKind, currentCodeCompletion().text()))
|
|
|
|
|
priority *= 100;
|
|
|
|
|
|
|
|
|
|
currentCodeCompletion_.setPriority(priority);
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-01 18:51:55 +02:00
|
|
|
bool CodeCompletionsExtractor::hasText(const Utf8String &text, CXCompletionString cxCompletionString) const
|
|
|
|
|
{
|
|
|
|
|
const uint completionChunkCount = clang_getNumCompletionChunks(cxCompletionString);
|
|
|
|
|
|
|
|
|
|
for (uint chunkIndex = 0; chunkIndex < completionChunkCount; ++chunkIndex) {
|
|
|
|
|
const CXCompletionChunkKind chunkKind = clang_getCompletionChunkKind(cxCompletionString, chunkIndex);
|
|
|
|
|
if (chunkKind == CXCompletionChunk_TypedText) {
|
|
|
|
|
const ClangString currentText(clang_getCompletionChunkText(cxCompletionString, chunkIndex));
|
|
|
|
|
return text == currentText;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const CodeCompletion &CodeCompletionsExtractor::currentCodeCompletion() const
|
|
|
|
|
{
|
|
|
|
|
return currentCodeCompletion_;
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-13 18:23:05 +02:00
|
|
|
std::ostream &operator<<(std::ostream &os, const CodeCompletionsExtractor &extractor)
|
2015-06-01 18:51:55 +02:00
|
|
|
{
|
2017-06-13 18:23:05 +02:00
|
|
|
os << "name: " << extractor.currentCodeCompletion().text()
|
|
|
|
|
<< ", kind: " << extractor.currentCodeCompletion().completionKind()
|
|
|
|
|
<< ", priority: " << extractor.currentCodeCompletion().priority()
|
|
|
|
|
<< ", kind: " << extractor.currentCodeCompletion().availability();
|
|
|
|
|
|
|
|
|
|
return os;
|
2015-06-01 18:51:55 +02:00
|
|
|
}
|
|
|
|
|
|
2015-06-16 11:56:00 +02:00
|
|
|
} // namespace ClangBackEnd
|
2015-06-01 18:51:55 +02:00
|
|
|
|