/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ****************************************************************************/ #include "codecompletionsextractor.h" #include "clangstring.h" #include "codecompletionchunkconverter.h" #ifdef CLANGBACKEND_TESTS #include #endif #include namespace ClangBackEnd { 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(); extractBriefComment(); extractCompletionChunks(); adaptPriority(); 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; } CodeCompletions CodeCompletionsExtractor::extractAll() { CodeCompletions codeCompletions; codeCompletions.reserve(cxCodeCompleteResults->NumResults); 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: case CXCursor_ConversionFunction: 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; case CXCursor_TypedefDecl: case CXCursor_TypeAliasDecl: currentCodeCompletion_.setCompletionKind(CodeCompletion::TypeAliasCompletionKind); break; 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; 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; } } } void CodeCompletionsExtractor::extractBriefComment() { ClangString briefComment = clang_getCompletionBriefComment(currentCxCodeCompleteResult.CompletionString); currentCodeCompletion_.setBriefComment(briefComment); } void CodeCompletionsExtractor::extractCompletionChunks() { currentCodeCompletion_.setChunks(CodeCompletionChunkConverter::extract(currentCxCodeCompleteResult.CompletionString)); } void CodeCompletionsExtractor::adaptPriority() { decreasePriorityForDestructors(); decreasePriorityForNonAvailableCompletions(); decreasePriorityForQObjectInternals(); decreasePriorityForSignals(); decreasePriorityForOperators(); } 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); } 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); } 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_; } #ifdef CLANGBACKEND_TESTS void PrintTo(const CodeCompletionsExtractor &extractor, std::ostream *os) { *os << "name: " << ::testing::PrintToString(extractor.currentCodeCompletion().text()) << ", kind: " << ::testing::PrintToString(extractor.currentCodeCompletion().completionKind()) << ", priority: " << extractor.currentCodeCompletion().priority() << ", kind: " << ::testing::PrintToString(extractor.currentCodeCompletion().availability()); } #endif } // namespace ClangBackEnd