From 6da7babc4a7797c8442d80201d1fe50dfe35ea7d Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Wed, 27 Apr 2022 16:02:08 +0200 Subject: [PATCH] ClangCodeModel: Remove libclang-based completion and function hints Change-Id: I742fb14b1aba3ba1f35a5c80bf553d2a735cac48 Reviewed-by: David Schulz --- src/plugins/clangcodemodel/CMakeLists.txt | 9 - ...langactivationsequencecontextprocessor.cpp | 7 - .../clangactivationsequencecontextprocessor.h | 3 - .../clangassistproposalitem.cpp | 536 ----------- .../clangcodemodel/clangassistproposalitem.h | 80 -- .../clangassistproposalmodel.cpp | 68 -- .../clangcodemodel/clangassistproposalmodel.h | 49 - .../clangbackendcommunicator.cpp | 35 - .../clangcodemodel/clangbackendcommunicator.h | 12 - .../clangcodemodel/clangbackendreceiver.cpp | 52 -- .../clangcodemodel/clangbackendreceiver.h | 9 - src/plugins/clangcodemodel/clangcodemodel.qbs | 18 - .../clangcodemodel/clangcodemodelplugin.cpp | 2 - .../clangcompletionassistinterface.cpp | 81 -- .../clangcompletionassistinterface.h | 69 -- .../clangcompletionassistprocessor.cpp | 718 --------------- .../clangcompletionassistprocessor.h | 117 --- .../clangcompletionassistprovider.cpp | 87 -- .../clangcompletionassistprovider.h | 61 -- .../clangcompletionchunkstotextconverter.cpp | 366 -------- .../clangcompletionchunkstotextconverter.h | 114 --- .../clangcompletioncontextanalyzer.cpp | 10 +- .../clangcompletioncontextanalyzer.h | 5 - src/plugins/clangcodemodel/clangdclient.cpp | 105 ++- .../clangeditordocumentprocessor.cpp | 2 +- .../clangcodemodel/clangfunctionhintmodel.cpp | 125 --- .../clangcodemodel/clangfunctionhintmodel.h | 52 -- .../clangmodelmanagersupport.cpp | 9 +- .../clangcodemodel/clangmodelmanagersupport.h | 4 +- .../test/clangautomationutils.cpp | 140 --- .../test/clangautomationutils.h | 46 - .../test/clangbatchfileprocessor.cpp | 42 - .../test/clangcodecompletion_test.cpp | 846 ------------------ .../test/clangcodecompletion_test.h | 70 -- .../clangcodemodel/test/clangdtests.cpp | 6 +- src/plugins/cppeditor/cppmodelmanager.cpp | 4 +- tests/unit/unittest/CMakeLists.txt | 6 - ...ctivationsequencecontextprocessor-test.cpp | 221 ----- .../clangcompletioncontextanalyzer-test.cpp | 589 ------------ .../completionchunkstotextconverter-test.cpp | 379 -------- tests/unit/unittest/unittest.qbs | 9 - 41 files changed, 115 insertions(+), 5048 deletions(-) delete mode 100644 src/plugins/clangcodemodel/clangassistproposalitem.cpp delete mode 100644 src/plugins/clangcodemodel/clangassistproposalitem.h delete mode 100644 src/plugins/clangcodemodel/clangassistproposalmodel.cpp delete mode 100644 src/plugins/clangcodemodel/clangassistproposalmodel.h delete mode 100644 src/plugins/clangcodemodel/clangcompletionassistinterface.cpp delete mode 100644 src/plugins/clangcodemodel/clangcompletionassistinterface.h delete mode 100644 src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp delete mode 100644 src/plugins/clangcodemodel/clangcompletionassistprocessor.h delete mode 100644 src/plugins/clangcodemodel/clangcompletionassistprovider.cpp delete mode 100644 src/plugins/clangcodemodel/clangcompletionassistprovider.h delete mode 100644 src/plugins/clangcodemodel/clangcompletionchunkstotextconverter.cpp delete mode 100644 src/plugins/clangcodemodel/clangcompletionchunkstotextconverter.h delete mode 100644 src/plugins/clangcodemodel/clangfunctionhintmodel.cpp delete mode 100644 src/plugins/clangcodemodel/clangfunctionhintmodel.h delete mode 100644 src/plugins/clangcodemodel/test/clangautomationutils.cpp delete mode 100644 src/plugins/clangcodemodel/test/clangautomationutils.h delete mode 100644 src/plugins/clangcodemodel/test/clangcodecompletion_test.cpp delete mode 100644 src/plugins/clangcodemodel/test/clangcodecompletion_test.h delete mode 100644 tests/unit/unittest/activationsequencecontextprocessor-test.cpp delete mode 100644 tests/unit/unittest/clangcompletioncontextanalyzer-test.cpp delete mode 100644 tests/unit/unittest/completionchunkstotextconverter-test.cpp diff --git a/src/plugins/clangcodemodel/CMakeLists.txt b/src/plugins/clangcodemodel/CMakeLists.txt index 0ec53e69060..f9798dfaa46 100644 --- a/src/plugins/clangcodemodel/CMakeLists.txt +++ b/src/plugins/clangcodemodel/CMakeLists.txt @@ -11,17 +11,11 @@ add_qtc_plugin(ClangCodeModel SOURCES clangactivationsequencecontextprocessor.cpp clangactivationsequencecontextprocessor.h clangactivationsequenceprocessor.cpp clangactivationsequenceprocessor.h - clangassistproposalitem.cpp clangassistproposalitem.h - clangassistproposalmodel.cpp clangassistproposalmodel.h clangbackendcommunicator.cpp clangbackendcommunicator.h clangbackendlogging.cpp clangbackendlogging.h clangbackendreceiver.cpp clangbackendreceiver.h clangbackendsender.cpp clangbackendsender.h clangcodemodelplugin.cpp clangcodemodelplugin.h - clangcompletionassistinterface.cpp clangcompletionassistinterface.h - clangcompletionassistprocessor.cpp clangcompletionassistprocessor.h - clangcompletionassistprovider.cpp clangcompletionassistprovider.h - clangcompletionchunkstotextconverter.cpp clangcompletionchunkstotextconverter.h clangcompletioncontextanalyzer.cpp clangcompletioncontextanalyzer.h clangconstants.h clangdclient.cpp clangdclient.h @@ -32,7 +26,6 @@ add_qtc_plugin(ClangCodeModel clangeditordocumentprocessor.cpp clangeditordocumentprocessor.h clangfixitoperation.cpp clangfixitoperation.h clangfixitoperationsextractor.cpp clangfixitoperationsextractor.h - clangfunctionhintmodel.cpp clangfunctionhintmodel.h clangdlocatorfilters.cpp clangdlocatorfilters.h clangmodelmanagersupport.cpp clangmodelmanagersupport.h clangpreprocessorassistproposalitem.cpp clangpreprocessorassistproposalitem.h @@ -57,9 +50,7 @@ extend_qtc_plugin(ClangCodeModel extend_qtc_plugin(ClangCodeModel CONDITION WITH_TESTS SOURCES - test/clangautomationutils.cpp test/clangautomationutils.h test/clangbatchfileprocessor.cpp test/clangbatchfileprocessor.h - test/clangcodecompletion_test.cpp test/clangcodecompletion_test.h test/clangdtests.cpp test/clangdtests.h test/data/clangtestdata.qrc ) diff --git a/src/plugins/clangcodemodel/clangactivationsequencecontextprocessor.cpp b/src/plugins/clangcodemodel/clangactivationsequencecontextprocessor.cpp index 0eaffa3f724..db5e71bde43 100644 --- a/src/plugins/clangcodemodel/clangactivationsequencecontextprocessor.cpp +++ b/src/plugins/clangcodemodel/clangactivationsequencecontextprocessor.cpp @@ -52,13 +52,6 @@ ActivationSequenceContextProcessor::ActivationSequenceContextProcessor( process(); } -ActivationSequenceContextProcessor::ActivationSequenceContextProcessor( - const ClangCompletionAssistInterface *interface) - : ActivationSequenceContextProcessor(interface->textDocument(), interface->position(), - interface->languageFeatures()) -{ -} - CPlusPlus::Kind ActivationSequenceContextProcessor::completionKind() const { return m_completionKind; diff --git a/src/plugins/clangcodemodel/clangactivationsequencecontextprocessor.h b/src/plugins/clangcodemodel/clangactivationsequencecontextprocessor.h index c735ce419ef..aa457dfeb92 100644 --- a/src/plugins/clangcodemodel/clangactivationsequencecontextprocessor.h +++ b/src/plugins/clangcodemodel/clangactivationsequencecontextprocessor.h @@ -25,8 +25,6 @@ #pragma once -#include - #include #include @@ -43,7 +41,6 @@ class ActivationSequenceContextProcessor public: ActivationSequenceContextProcessor(QTextDocument *document, int position, CPlusPlus::LanguageFeatures languageFeatures); - ActivationSequenceContextProcessor(const ClangCompletionAssistInterface *interface); CPlusPlus::Kind completionKind() const; int startOfNamePosition() const; // e.g. points to 'b' in "foo.bar" diff --git a/src/plugins/clangcodemodel/clangassistproposalitem.cpp b/src/plugins/clangcodemodel/clangassistproposalitem.cpp deleted file mode 100644 index 068355ef911..00000000000 --- a/src/plugins/clangcodemodel/clangassistproposalitem.cpp +++ /dev/null @@ -1,536 +0,0 @@ -/**************************************************************************** -** -** 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 "clangassistproposalitem.h" - -#include "clangcompletionchunkstotextconverter.h" -#include "clangfixitoperation.h" -#include "clangutils.h" - -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -using namespace CPlusPlus; -using namespace ClangBackEnd; -using namespace TextEditor; -using namespace Utils; - -namespace ClangCodeModel { -namespace Internal { - -bool ClangAssistProposalItem::prematurelyApplies(const QChar &typedCharacter) const -{ - bool applies = false; - - if (m_completionOperator == T_SIGNAL || m_completionOperator == T_SLOT) - applies = QString::fromLatin1("(,").contains(typedCharacter); - else if (m_completionOperator == T_STRING_LITERAL || m_completionOperator == T_ANGLE_STRING_LITERAL) - applies = (typedCharacter == QLatin1Char('/')) && text().endsWith(QLatin1Char('/')); - else if (firstCodeCompletion().completionKind == CodeCompletion::ObjCMessageCompletionKind) - applies = QString::fromLatin1(";.,").contains(typedCharacter); - else - applies = QString::fromLatin1(";.,:(").contains(typedCharacter); - - if (applies) - m_typedCharacter = typedCharacter; - - return applies; -} - -bool ClangAssistProposalItem::implicitlyApplies() const -{ - return true; -} - -static QString methodDefinitionParameters(const CodeCompletionChunks &chunks) -{ - QString result; - - auto typedTextChunkIt = std::find_if(chunks.cbegin(), chunks.cend(), - [](const CodeCompletionChunk &chunk) { - return chunk.kind == CodeCompletionChunk::TypedText; - }); - if (typedTextChunkIt == chunks.cend()) - return result; - - std::for_each(++typedTextChunkIt, chunks.cend(), [&result](const CodeCompletionChunk &chunk) { - if (chunk.kind == CodeCompletionChunk::Placeholder && chunk.text.contains('=')) { - Utf8String text = chunk.text.mid(0, chunk.text.indexOf('=')); - if (text.endsWith(' ')) - text.chop(1); - result += text; - } else { - result += chunk.text; - } - }); - - return result; -} - -static bool skipParenForFunctionLikeSnippet(const std::vector &placeholderPositions, - const QString &text, - int position) -{ - return placeholderPositions.size() == 1 - && position > 0 - && text[position - 1] == '(' - && text[position] == ')' - && position + 1 == text.size(); -} - -static bool isFuncDeclAsSingleTypedText(const CodeCompletion &completion) -{ - // There is no libclang API to tell function call items from declaration items apart. - // However, the chunks differ for these items (c-index-test -code-completion-at=...): - // An (override) declaration (available in derived class scope): - // CXXMethod:{TypedText void hello() override} (40) - // A function call: - // CXXMethod:{ResultType void}{TypedText hello}{LeftParen (}{RightParen )} (36) - return completion.completionKind == CodeCompletion::FunctionDefinitionCompletionKind - && completion.chunks.size() == 1 - && completion.chunks[0].kind == CodeCompletionChunk::TypedText; -} - -void ClangAssistProposalItem::apply(TextDocumentManipulatorInterface &manipulator, - int basePosition) const -{ - const CodeCompletion ccr = firstCodeCompletion(); - - if (!ccr.requiredFixIts.empty()) { - // Important: Calculate shift before changing the document. - basePosition += fixItsShift(manipulator); - - ClangFixItOperation fixItOperation(Utf8String(), ccr.requiredFixIts); - fixItOperation.perform(); - } - - QString textToBeInserted = m_text; - QString extraCharacters; - int extraLength = 0; - int cursorOffset = 0; - bool setAutoCompleteSkipPos = false; - int currentPosition = manipulator.currentPosition(); - - if (m_completionOperator == T_SIGNAL || m_completionOperator == T_SLOT) { - extraCharacters += QLatin1Char(')'); - if (m_typedCharacter == QLatin1Char('(')) // Eat the opening parenthesis - m_typedCharacter = QChar(); - } else if (ccr.completionKind == CodeCompletion::KeywordCompletionKind) { - CompletionChunksToTextConverter converter; - converter.setupForKeywords(); - converter.parseChunks(ccr.chunks); - - textToBeInserted = converter.text(); - - if (converter.hasPlaceholderPositions()) { - const std::vector &placeholderPositions = converter.placeholderPositions(); - const int position = placeholderPositions[0]; - cursorOffset = position - converter.text().size(); - // If the snippet looks like a function call, e.g. "sizeof()", - // ensure that we can "overtype" ')' after inserting it. - setAutoCompleteSkipPos = skipParenForFunctionLikeSnippet(placeholderPositions, - textToBeInserted, - position); - } - } else if (ccr.completionKind == CodeCompletion::NamespaceCompletionKind) { - CompletionChunksToTextConverter converter; - converter.parseChunks(ccr.chunks); // Appends "::" after name space name - textToBeInserted = converter.text(); - - // Clang does not provide the "::" chunk consistently for namespaces, e.g. - // - // namespace a { namespace b { namespace c {} } } - // // complete "a" ==> "a::" - // a:: // complete "b" ==> "b", not "b::" - // - // Remove "::" to avoid any confusion for now. - if (textToBeInserted.endsWith("::")) - textToBeInserted.chop(2); - } else if (!ccr.text.isEmpty()) { - const CompletionSettings &completionSettings = - TextEditorSettings::completionSettings(); - const bool autoInsertBrackets = completionSettings.m_autoInsertBrackets; - - if (autoInsertBrackets && - (ccr.completionKind == CodeCompletion::FunctionCompletionKind - || ccr.completionKind == CodeCompletion::FunctionDefinitionCompletionKind - || ccr.completionKind == CodeCompletion::DestructorCompletionKind - || ccr.completionKind == CodeCompletion::ConstructorCompletionKind - || ccr.completionKind == CodeCompletion::SignalCompletionKind - || ccr.completionKind == CodeCompletion::SlotCompletionKind)) { - // When the user typed the opening parenthesis, he'll likely also type the closing one, - // in which case it would be annoying if we put the cursor after the already automatically - // inserted closing parenthesis. - const bool skipClosingParenthesis = m_typedCharacter != QLatin1Char('('); - QTextCursor cursor = manipulator.textCursorAt(basePosition); - - bool abandonParen = false; - if (matchPreviousWord(manipulator, cursor, "&")) { - moveToPreviousWord(manipulator, cursor); - moveToPreviousChar(manipulator, cursor); - const QChar prevChar = manipulator.characterAt(cursor.position()); - cursor.setPosition(basePosition); - abandonParen = QString("(;,{}").contains(prevChar); - } - if (!abandonParen) { - const bool isFullDecl = isFuncDeclAsSingleTypedText(ccr); - if (isFullDecl) - extraCharacters += QLatin1Char(';'); - abandonParen = isAtUsingDeclaration(manipulator, basePosition) || isFullDecl; - } - - if (!abandonParen && ccr.completionKind == CodeCompletion::FunctionDefinitionCompletionKind) { - const CodeCompletionChunk resultType = ccr.chunks.first(); - if (resultType.kind == CodeCompletionChunk::ResultType) { - if (matchPreviousWord(manipulator, cursor, resultType.text.toString())) { - extraCharacters += methodDefinitionParameters(ccr.chunks); - // To skip the next block. - abandonParen = true; - } - } else { - // Do nothing becasue it's not a function definition. - - // It's a clang bug that the function might miss a ResultType chunk - // when the base class method is called from the overriding method - // of the derived class. For example: - // void Derived::foo() override { Base:: } - } - } - if (!abandonParen) { - if (completionSettings.m_spaceAfterFunctionName) - extraCharacters += QLatin1Char(' '); - extraCharacters += QLatin1Char('('); - if (m_typedCharacter == QLatin1Char('(')) - m_typedCharacter = QChar(); - - // If the function doesn't return anything, automatically place the semicolon, - // unless we're doing a scope completion (then it might be function definition). - const QChar characterAtCursor = manipulator.characterAt(currentPosition); - bool endWithSemicolon = m_typedCharacter == QLatin1Char(';')/* - || (function->returnType()->isVoidType() && m_completionOperator != T_COLON_COLON)*/; //### - const QChar semicolon = m_typedCharacter.isNull() ? QLatin1Char(';') : m_typedCharacter; - - if (endWithSemicolon && characterAtCursor == semicolon) { - endWithSemicolon = false; - m_typedCharacter = QChar(); - } - - // If the function takes no arguments, automatically place the closing parenthesis - if (!hasOverloadsWithParameters() && !ccr.hasParameters && skipClosingParenthesis) { - extraCharacters += QLatin1Char(')'); - if (endWithSemicolon) { - extraCharacters += semicolon; - m_typedCharacter = QChar(); - } - } else { - const QChar lookAhead = manipulator.characterAt(manipulator.currentPosition() + 1); - if (MatchingText::shouldInsertMatchingText(lookAhead)) { - extraCharacters += QLatin1Char(')'); - --cursorOffset; - setAutoCompleteSkipPos = true; - if (endWithSemicolon) { - extraCharacters += semicolon; - --cursorOffset; - m_typedCharacter = QChar(); - } - } - } - } - } - } - - // Append an unhandled typed character, adjusting cursor offset when it had been adjusted before - if (!m_typedCharacter.isNull()) { - extraCharacters += m_typedCharacter; - if (cursorOffset != 0) - --cursorOffset; - } - - // Avoid inserting characters that are already there - QTextCursor cursor = manipulator.textCursorAt(basePosition); - cursor.movePosition(QTextCursor::EndOfWord); - const QString textAfterCursor = manipulator.textAt(currentPosition, - cursor.position() - currentPosition); - - if (textToBeInserted != textAfterCursor - && textToBeInserted.indexOf(textAfterCursor, currentPosition - basePosition) >= 0) { - currentPosition = cursor.position(); - } - - for (int i = 0; i < extraCharacters.length(); ++i) { - const QChar a = extraCharacters.at(i); - const QChar b = manipulator.characterAt(currentPosition + i); - if (a == b) - ++extraLength; - else - break; - } - - textToBeInserted += extraCharacters; - - const int length = currentPosition - basePosition + extraLength; - - const bool isReplaced = manipulator.replace(basePosition, length, textToBeInserted); - manipulator.setCursorPosition(basePosition + textToBeInserted.length()); - if (isReplaced) { - if (cursorOffset) - manipulator.setCursorPosition(manipulator.currentPosition() + cursorOffset); - if (setAutoCompleteSkipPos) - manipulator.setAutoCompleteSkipPosition(manipulator.currentPosition()); - - if (ccr.completionKind == CodeCompletion::KeywordCompletionKind) - manipulator.autoIndent(basePosition, textToBeInserted.size()); - } -} - -void ClangAssistProposalItem::setText(const QString &text) -{ - m_text = text; -} - -QString ClangAssistProposalItem::text() const -{ - return m_text; -} - -const QVector &ClangAssistProposalItem::firstCompletionFixIts() const -{ - return firstCodeCompletion().requiredFixIts; -} - -std::pair fixItPositionsRange(const FixItContainer &fixIt, const QTextCursor &cursor) -{ - const QTextBlock startLine = cursor.document()->findBlockByNumber(fixIt.range.start.line - 1); - const QTextBlock endLine = cursor.document()->findBlockByNumber(fixIt.range.end.line - 1); - - const int fixItStartPos = Text::positionInText( - cursor.document(), - fixIt.range.start.line, - cppEditorColumn(startLine, fixIt.range.start.column)); - const int fixItEndPos = Text::positionInText( - cursor.document(), - fixIt.range.end.line, - cppEditorColumn(endLine, fixIt.range.end.column)); - return std::make_pair(fixItStartPos, fixItEndPos); -} - -static QString textReplacedByFixit(const FixItContainer &fixIt) -{ - TextEditorWidget *textEditorWidget = TextEditorWidget::currentTextEditorWidget(); - if (!textEditorWidget) - return QString(); - const std::pair fixItPosRange = fixItPositionsRange(fixIt, - textEditorWidget->textCursor()); - return textEditorWidget->textAt(fixItPosRange.first, - fixItPosRange.second - fixItPosRange.first); -} - -QString ClangAssistProposalItem::fixItText() const -{ - const FixItContainer &fixIt = firstCompletionFixIts().first(); - return QCoreApplication::translate("ClangCodeModel::ClangAssistProposalItem", - "Requires changing \"%1\" to \"%2\"") - .arg(textReplacedByFixit(fixIt), fixIt.text.toString()); -} - -int ClangAssistProposalItem::fixItsShift(const TextDocumentManipulatorInterface &manipulator) const -{ - const QVector &requiredFixIts = firstCompletionFixIts(); - if (requiredFixIts.empty()) - return 0; - - int shift = 0; - const QTextCursor cursor = manipulator.textCursorAt(0); - for (const FixItContainer &fixIt : requiredFixIts) { - const std::pair fixItPosRange = fixItPositionsRange(fixIt, cursor); - shift += fixIt.text.toString().length() - (fixItPosRange.second - fixItPosRange.first); - } - return shift; -} - -QIcon ClangAssistProposalItem::icon() const -{ - using namespace CPlusPlus::Icons; - static const char SNIPPET_ICON_PATH[] = ":/texteditor/images/snippet.png"; - static const QIcon snippetIcon = QIcon(QLatin1String(SNIPPET_ICON_PATH)); - - const ClangBackEnd::CodeCompletion &completion = firstCodeCompletion(); - switch (completion.completionKind) { - case CodeCompletion::ClassCompletionKind: - case CodeCompletion::TemplateClassCompletionKind: - case CodeCompletion::TypeAliasCompletionKind: - return CodeModelIcon::iconForType(CodeModelIcon::Class); - case CodeCompletion::EnumerationCompletionKind: - return CodeModelIcon::iconForType(CodeModelIcon::Enum); - case CodeCompletion::EnumeratorCompletionKind: - return CodeModelIcon::iconForType(CodeModelIcon::Enumerator); - case CodeCompletion::ConstructorCompletionKind: - case CodeCompletion::DestructorCompletionKind: - case CodeCompletion::FunctionCompletionKind: - case CodeCompletion::FunctionDefinitionCompletionKind: - case CodeCompletion::TemplateFunctionCompletionKind: - case CodeCompletion::ObjCMessageCompletionKind: - switch (completion.availability) { - case CodeCompletion::Available: - case CodeCompletion::Deprecated: - return CodeModelIcon::iconForType(CodeModelIcon::FuncPublic); - default: - return CodeModelIcon::iconForType(CodeModelIcon::FuncPrivate); - } - case CodeCompletion::SignalCompletionKind: - return CodeModelIcon::iconForType(CodeModelIcon::Signal); - case CodeCompletion::SlotCompletionKind: - switch (completion.availability) { - case CodeCompletion::Available: - case CodeCompletion::Deprecated: - return CodeModelIcon::iconForType(CodeModelIcon::SlotPublic); - case CodeCompletion::NotAccessible: - case CodeCompletion::NotAvailable: - return CodeModelIcon::iconForType(CodeModelIcon::SlotPrivate); - } - break; - case CodeCompletion::NamespaceCompletionKind: - return CodeModelIcon::iconForType(CodeModelIcon::Namespace); - case CodeCompletion::PreProcessorCompletionKind: - return CodeModelIcon::iconForType(CodeModelIcon::Macro); - case CodeCompletion::VariableCompletionKind: - switch (completion.availability) { - case CodeCompletion::Available: - case CodeCompletion::Deprecated: - return CodeModelIcon::iconForType(CodeModelIcon::VarPublic); - default: - return CodeModelIcon::iconForType(CodeModelIcon::VarPrivate); - } - case CodeCompletion::KeywordCompletionKind: - return CodeModelIcon::iconForType(CodeModelIcon::Keyword); - case CodeCompletion::ClangSnippetKind: - return snippetIcon; - case CodeCompletion::Other: - return CodeModelIcon::iconForType(CodeModelIcon::Unknown); - default: - break; - } - - return QIcon(); -} - -QString ClangAssistProposalItem::detail() const -{ - QString detail; - for (const ClangBackEnd::CodeCompletion &codeCompletion : m_codeCompletions) { - if (!detail.isEmpty()) - detail += "
"; - detail += CompletionChunksToTextConverter::convertToToolTipWithHtml( - codeCompletion.chunks, codeCompletion.completionKind); - - if (!codeCompletion.briefComment.isEmpty()) - detail += "
" + codeCompletion.briefComment.toString(); - } - - if (requiresFixIts()) - detail += "

" + fixItText() + ""; - - return detail; -} - -bool ClangAssistProposalItem::isKeyword() const -{ - // KeywordCompletionKind includes real keywords but also "code patterns"/snippets. - return m_codeCompletions[0].completionKind == CodeCompletion::KeywordCompletionKind; -} - -Qt::TextFormat ClangAssistProposalItem::detailFormat() const -{ - return Qt::RichText; -} - -bool ClangAssistProposalItem::isSnippet() const -{ - return false; -} - -bool ClangAssistProposalItem::isValid() const -{ - return true; -} - -quint64 ClangAssistProposalItem::hash() const -{ - return 0; -} - -bool ClangAssistProposalItem::requiresFixIts() const -{ - return !firstCompletionFixIts().empty(); -} - -bool ClangAssistProposalItem::hasOverloadsWithParameters() const -{ - return m_hasOverloadsWithParameters; -} - -void ClangAssistProposalItem::setHasOverloadsWithParameters(bool hasOverloadsWithParameters) -{ - m_hasOverloadsWithParameters = hasOverloadsWithParameters; -} - -void ClangAssistProposalItem::keepCompletionOperator(unsigned compOp) -{ - m_completionOperator = compOp; -} - -void ClangAssistProposalItem::appendCodeCompletion(const CodeCompletion &codeCompletion) -{ - m_codeCompletions.push_back(codeCompletion); -} - -const ClangBackEnd::CodeCompletion &ClangAssistProposalItem::firstCodeCompletion() const -{ - return m_codeCompletions.at(0); -} - -void ClangAssistProposalItem::removeFirstCodeCompletion() -{ - QTC_ASSERT(!m_codeCompletions.empty(), return;); - m_codeCompletions.erase(m_codeCompletions.begin()); -} - -} // namespace Internal -} // namespace ClangCodeModel diff --git a/src/plugins/clangcodemodel/clangassistproposalitem.h b/src/plugins/clangcodemodel/clangassistproposalitem.h deleted file mode 100644 index 64eb8789b34..00000000000 --- a/src/plugins/clangcodemodel/clangassistproposalitem.h +++ /dev/null @@ -1,80 +0,0 @@ -/**************************************************************************** -** -** 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. -** -****************************************************************************/ - -#pragma once - -#include - -#include - -#include - -namespace ClangCodeModel { -namespace Internal { - -class ClangAssistProposalItem final : public TextEditor::AssistProposalItemInterface -{ - friend bool operator<(const ClangAssistProposalItem &first, const ClangAssistProposalItem &second); -public: - ~ClangAssistProposalItem() noexcept override = default; - bool prematurelyApplies(const QChar &typedCharacter) const final; - bool implicitlyApplies() const final; - void apply(TextEditor::TextDocumentManipulatorInterface &manipulator, int basePosition) const final; - - void setText(const QString &text); - QString text() const final; - QIcon icon() const final; - QString detail() const final; - bool isKeyword() const final; - Qt::TextFormat detailFormat() const final; - bool isSnippet() const final; - bool isValid() const final; - quint64 hash() const final; - bool requiresFixIts() const final; - - void keepCompletionOperator(unsigned compOp); - - bool hasOverloadsWithParameters() const; - void setHasOverloadsWithParameters(bool hasOverloadsWithParameters); - - void appendCodeCompletion(const ClangBackEnd::CodeCompletion &firstCodeCompletion); - const ClangBackEnd::CodeCompletion &firstCodeCompletion() const; - void removeFirstCodeCompletion(); - -private: - const QVector &firstCompletionFixIts() const; - QString fixItText() const; - int fixItsShift(const TextEditor::TextDocumentManipulatorInterface &manipulator) const; - - std::vector m_codeCompletions; - QList m_overloads; - bool m_hasOverloadsWithParameters = false; - QString m_text; - unsigned m_completionOperator; - mutable QChar m_typedCharacter; -}; - -} // namespace Internal -} // namespace ClangCodeModel diff --git a/src/plugins/clangcodemodel/clangassistproposalmodel.cpp b/src/plugins/clangcodemodel/clangassistproposalmodel.cpp deleted file mode 100644 index 9f682ff6eb3..00000000000 --- a/src/plugins/clangcodemodel/clangassistproposalmodel.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/**************************************************************************** -** -** 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 "clangassistproposalitem.h" - -#include "clangassistproposalmodel.h" - -#include - -#include - -namespace ClangCodeModel { -namespace Internal { - -constexpr int SORT_LIMIT = 30000; - -bool ClangAssistProposalModel::containsDuplicates() const -{ - return false; -} - -bool ClangAssistProposalModel::isSortable(const QString &/*prefix*/) const -{ - return m_currentItems.size() <= SORT_LIMIT; -} - -void ClangAssistProposalModel::sort(const QString &/*prefix*/) -{ - using TextEditor::AssistProposalItemInterface; - - auto currentItemsCompare = [](AssistProposalItemInterface *first, - AssistProposalItemInterface *second) { - if (first->proposalMatch() != second->proposalMatch()) { - return static_cast(first->proposalMatch()) - < static_cast(second->proposalMatch()); - } - return false; - }; - - // Keep the order for the items with the same priority and name. - std::stable_sort(m_currentItems.begin(), m_currentItems.end(), currentItemsCompare); -} - -} // namespace Internal -} // namespace ClangCodeModel - diff --git a/src/plugins/clangcodemodel/clangassistproposalmodel.h b/src/plugins/clangcodemodel/clangassistproposalmodel.h deleted file mode 100644 index cb2cb7edd36..00000000000 --- a/src/plugins/clangcodemodel/clangassistproposalmodel.h +++ /dev/null @@ -1,49 +0,0 @@ -/**************************************************************************** -** -** 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. -** -****************************************************************************/ - -#pragma once - -#include - -#include - -#include - -namespace ClangCodeModel { -namespace Internal { - -class ClangAssistProposalModel : public TextEditor::GenericProposalModel -{ -public: - ClangAssistProposalModel() = default; - - bool containsDuplicates() const override; - - bool isSortable(const QString &prefix) const override; - void sort(const QString &prefix) override; -}; - -} // namespace Internal -} // namespace ClangCodeModel diff --git a/src/plugins/clangcodemodel/clangbackendcommunicator.cpp b/src/plugins/clangcodemodel/clangbackendcommunicator.cpp index 029df103329..c1b3ace7d22 100644 --- a/src/plugins/clangcodemodel/clangbackendcommunicator.cpp +++ b/src/plugins/clangcodemodel/clangbackendcommunicator.cpp @@ -26,7 +26,6 @@ #include "clangbackendcommunicator.h" #include "clangbackendlogging.h" -#include "clangcompletionassistprocessor.h" #include "clangmodelmanagersupport.h" #include "clangutils.h" @@ -99,8 +98,6 @@ BackendCommunicator::BackendCommunicator() m_receiver.setAliveHandler([this]() { m_connection.resetProcessAliveTimer(); }); - connect(Core::EditorManager::instance(), &Core::EditorManager::editorAboutToClose, - this, &BackendCommunicator::onEditorAboutToClose); connect(Core::ICore::instance(), &Core::ICore::coreAboutToClose, this, &BackendCommunicator::setupDummySender); auto globalFCB = GlobalFileChangeBlocker::instance(); @@ -192,11 +189,6 @@ void BackendCommunicator::documentVisibilityChanged() visibleCppEditorDocumentsFilePaths()); } -bool BackendCommunicator::isNotWaitingForCompletion() const -{ - return !m_receiver.isExpectingCompletionsMessage(); -} - void BackendCommunicator::setBackendJobsPostponed(bool postponed) { if (postponed) { @@ -349,12 +341,6 @@ void BackendCommunicator::onConnectedToBackend() initializeBackendWithCurrentData(); } -void BackendCommunicator::onEditorAboutToClose(Core::IEditor *editor) -{ - if (auto *textEditor = qobject_cast(editor)) - m_receiver.deleteProcessorsOfEditorWidget(textEditor->editorWidget()); -} - void BackendCommunicator::setupDummySender() { m_sender.reset(new DummyBackendSender); @@ -443,26 +429,5 @@ void BackendCommunicator::unsavedFilesRemoved(const FileContainers &fileContaine m_sender->unsavedFilesRemoved(message); } -void BackendCommunicator::requestCompletions(ClangCompletionAssistProcessor *assistProcessor, - const QString &filePath, - quint32 line, - quint32 column, - qint32 funcNameStartLine, - qint32 funcNameStartColumn) -{ - const RequestCompletionsMessage message(filePath, - line, - column, - funcNameStartLine, - funcNameStartColumn); - m_sender->requestCompletions(message); - m_receiver.addExpectedCompletionsMessage(message.ticketNumber, assistProcessor); -} - -void BackendCommunicator::cancelCompletions(TextEditor::IAssistProcessor *processor) -{ - m_receiver.cancelProcessor(processor); -} - } // namespace Internal } // namespace ClangCodeModel diff --git a/src/plugins/clangcodemodel/clangbackendcommunicator.h b/src/plugins/clangcodemodel/clangbackendcommunicator.h index 7487be17b1e..969427a2b01 100644 --- a/src/plugins/clangcodemodel/clangbackendcommunicator.h +++ b/src/plugins/clangcodemodel/clangbackendcommunicator.h @@ -48,8 +48,6 @@ namespace TextEditor { class IAssistProcessor; } namespace ClangCodeModel { namespace Internal { -class ClangCompletionAssistProcessor; - class BackendCommunicator : public QObject { Q_OBJECT @@ -84,16 +82,7 @@ public: void unsavedFilesUpdatedFromCppEditorDocument(const QString &filePath); void unsavedFilesRemoved(const FileContainers &fileContainers); - void requestCompletions(ClangCompletionAssistProcessor *assistProcessor, - const QString &filePath, - quint32 line, - quint32 column, - qint32 funcNameStartLine = -1, - qint32 funcNameStartColumn = -1); - void cancelCompletions(TextEditor::IAssistProcessor *processor); - void updateChangeContentStartPosition(const QString &filePath, int position); - bool isNotWaitingForCompletion() const; void setBackendJobsPostponed(bool postponed); @@ -107,7 +96,6 @@ private: void setupDummySender(); void onConnectedToBackend(); - void onEditorAboutToClose(Core::IEditor *editor); void logExecutableDoesNotExist(); void logRestartedDueToUnexpectedFinish(); diff --git a/src/plugins/clangcodemodel/clangbackendreceiver.cpp b/src/plugins/clangcodemodel/clangbackendreceiver.cpp index 8764022a67b..c1b435de4a8 100644 --- a/src/plugins/clangcodemodel/clangbackendreceiver.cpp +++ b/src/plugins/clangcodemodel/clangbackendreceiver.cpp @@ -27,7 +27,6 @@ #include "clangbackendlogging.h" -#include "clangcompletionassistprocessor.h" #include "clangeditordocumentprocessor.h" #include @@ -71,55 +70,8 @@ void BackendReceiver::setAliveHandler(const BackendReceiver::AliveHandler &handl m_aliveHandler = handler; } -void BackendReceiver::addExpectedCompletionsMessage( - quint64 ticket, - ClangCompletionAssistProcessor *processor) -{ - QTC_ASSERT(processor, return); - QTC_CHECK(!m_assistProcessorsTable.contains(ticket)); - m_assistProcessorsTable.insert(ticket, processor); -} - -void BackendReceiver::cancelProcessor(TextEditor::IAssistProcessor *processor) -{ - for (auto it = m_assistProcessorsTable.cbegin(), end = m_assistProcessorsTable.cend(); - it != end; ++it) - { - if (it.value() == processor) { - m_assistProcessorsTable.erase(it); - return; - } - } -} - -void BackendReceiver::deleteProcessorsOfEditorWidget(TextEditor::TextEditorWidget *textEditorWidget) -{ - QList toRemove; - for (auto it = m_assistProcessorsTable.cbegin(), end = m_assistProcessorsTable.cend(); - it != end; ++it) - { - ClangCompletionAssistProcessor *assistProcessor = it.value(); - if (assistProcessor->textEditorWidget() == textEditorWidget) { - delete assistProcessor; - toRemove.append(it.key()); - } - } - for (quint64 item : toRemove) - m_assistProcessorsTable.remove(item); -} - -bool BackendReceiver::isExpectingCompletionsMessage() const -{ - return !m_assistProcessorsTable.isEmpty(); -} - void BackendReceiver::reset() { - // Clean up waiting assist processors - for (ClangCompletionAssistProcessor *processor : m_assistProcessorsTable) - processor->setAsyncProposalAvailable(nullptr); - m_assistProcessorsTable.clear(); - // Clean up futures for references; TODO: Remove duplication for (ReferencesEntry &entry : m_referencesTable) { entry.futureInterface.cancel(); @@ -155,10 +107,6 @@ void BackendReceiver::completions(const ClangBackEnd::CompletionsMessage &messag { qCDebugIpc() << "CompletionsMessage with" << message.codeCompletions.size() << "items"; - - const quint64 ticket = message.ticketNumber; - if (ClangCompletionAssistProcessor *processor = m_assistProcessorsTable.take(ticket)) - processor->handleAvailableCompletions(message.codeCompletions); } void BackendReceiver::annotations(const ClangBackEnd::AnnotationsMessage &message) diff --git a/src/plugins/clangcodemodel/clangbackendreceiver.h b/src/plugins/clangcodemodel/clangbackendreceiver.h index 92bb878d359..beab2f611e6 100644 --- a/src/plugins/clangcodemodel/clangbackendreceiver.h +++ b/src/plugins/clangcodemodel/clangbackendreceiver.h @@ -43,8 +43,6 @@ class TextEditorWidget; namespace ClangCodeModel { namespace Internal { -class ClangCompletionAssistProcessor; - class BackendReceiver : public ClangBackEnd::ClangCodeModelClientInterface { public: @@ -54,12 +52,6 @@ public: using AliveHandler = std::function; void setAliveHandler(const AliveHandler &handler); - void addExpectedCompletionsMessage(quint64 ticket, ClangCompletionAssistProcessor *processor); - void cancelProcessor(TextEditor::IAssistProcessor *processor); - void deleteProcessorsOfEditorWidget(TextEditor::TextEditorWidget *textEditorWidget); - - bool isExpectingCompletionsMessage() const; - void reset(); private: @@ -74,7 +66,6 @@ private: private: AliveHandler m_aliveHandler; - QHash m_assistProcessorsTable; struct ReferencesEntry { ReferencesEntry() = default; diff --git a/src/plugins/clangcodemodel/clangcodemodel.qbs b/src/plugins/clangcodemodel/clangcodemodel.qbs index d3546657430..e0f5a5632f8 100644 --- a/src/plugins/clangcodemodel/clangcodemodel.qbs +++ b/src/plugins/clangcodemodel/clangcodemodel.qbs @@ -29,10 +29,6 @@ QtcPlugin { "clangactivationsequencecontextprocessor.h", "clangactivationsequenceprocessor.cpp", "clangactivationsequenceprocessor.h", - "clangassistproposalitem.cpp", - "clangassistproposalitem.h", - "clangassistproposalmodel.cpp", - "clangassistproposalmodel.h", "clangbackendcommunicator.cpp", "clangbackendcommunicator.h", "clangbackendlogging.cpp", @@ -43,14 +39,6 @@ QtcPlugin { "clangbackendsender.h", "clangcodemodelplugin.cpp", "clangcodemodelplugin.h", - "clangcompletionassistinterface.cpp", - "clangcompletionassistinterface.h", - "clangcompletionassistprocessor.cpp", - "clangcompletionassistprocessor.h", - "clangcompletionassistprovider.cpp", - "clangcompletionassistprovider.h", - "clangcompletionchunkstotextconverter.cpp", - "clangcompletionchunkstotextconverter.h", "clangcompletioncontextanalyzer.cpp", "clangcompletioncontextanalyzer.h", "clangconstants.h", @@ -72,8 +60,6 @@ QtcPlugin { "clangfixitoperation.h", "clangfixitoperationsextractor.cpp", "clangfixitoperationsextractor.h", - "clangfunctionhintmodel.cpp", - "clangfunctionhintmodel.h", "clangmodelmanagersupport.cpp", "clangmodelmanagersupport.h", "clangpreprocessorassistproposalitem.cpp", @@ -121,12 +107,8 @@ QtcPlugin { condition: qtc.testsEnabled prefix: "test/" files: [ - "clangautomationutils.cpp", - "clangautomationutils.h", "clangbatchfileprocessor.cpp", "clangbatchfileprocessor.h", - "clangcodecompletion_test.cpp", - "clangcodecompletion_test.h", "clangdtests.cpp", "clangdtests.h", "data/clangtestdata.qrc", diff --git a/src/plugins/clangcodemodel/clangcodemodelplugin.cpp b/src/plugins/clangcodemodel/clangcodemodelplugin.cpp index 3a13c4542db..f0ccd9ea9e7 100644 --- a/src/plugins/clangcodemodel/clangcodemodelplugin.cpp +++ b/src/plugins/clangcodemodel/clangcodemodelplugin.cpp @@ -31,7 +31,6 @@ #ifdef WITH_TESTS # include "test/clangbatchfileprocessor.h" -# include "test/clangcodecompletion_test.h" # include "test/clangdtests.h" #endif @@ -209,7 +208,6 @@ void ClangCodeModelPlugin::maybeHandleBatchFileAndExit() const QVector ClangCodeModelPlugin::createTestObjects() const { return { - new Tests::ClangCodeCompletionTest, new Tests::ClangdTestCompletion, new Tests::ClangdTestExternalChanges, new Tests::ClangdTestFindReferences, diff --git a/src/plugins/clangcodemodel/clangcompletionassistinterface.cpp b/src/plugins/clangcodemodel/clangcompletionassistinterface.cpp deleted file mode 100644 index 8f2b5a9ffb8..00000000000 --- a/src/plugins/clangcodemodel/clangcompletionassistinterface.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/**************************************************************************** -** -** 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 "clangcompletionassistinterface.h" - -#include - -namespace ClangCodeModel { -namespace Internal { - -ClangCompletionAssistInterface::ClangCompletionAssistInterface(BackendCommunicator &communicator, CompletionType type, - const TextEditor::TextEditorWidget *textEditorWidget, - int position, - const Utils::FilePath &fileName, - TextEditor::AssistReason reason, - const ProjectExplorer::HeaderPaths &headerPaths, - const CPlusPlus::LanguageFeatures &features) - : AssistInterface(textEditorWidget->document(), position, fileName, reason) - , m_communicator(communicator) - , m_type(type) - , m_headerPaths(headerPaths) - , m_languageFeatures(features) - , m_textEditorWidget(textEditorWidget) -{ -} - -bool ClangCompletionAssistInterface::objcEnabled() const -{ - return true; // TODO: -} - -const ProjectExplorer::HeaderPaths &ClangCompletionAssistInterface::headerPaths() const -{ - return m_headerPaths; -} - -CPlusPlus::LanguageFeatures ClangCompletionAssistInterface::languageFeatures() const -{ - return m_languageFeatures; -} - -void ClangCompletionAssistInterface::setHeaderPaths(const ProjectExplorer::HeaderPaths &headerPaths) -{ - m_headerPaths = headerPaths; -} - -const TextEditor::TextEditorWidget *ClangCompletionAssistInterface::textEditorWidget() const -{ - return m_textEditorWidget; -} - -BackendCommunicator &ClangCompletionAssistInterface::communicator() const -{ - return m_communicator; -} - -} // namespace Internal -} // namespace ClangCodeModel - diff --git a/src/plugins/clangcodemodel/clangcompletionassistinterface.h b/src/plugins/clangcodemodel/clangcompletionassistinterface.h deleted file mode 100644 index ce3f0921c8f..00000000000 --- a/src/plugins/clangcodemodel/clangcompletionassistinterface.h +++ /dev/null @@ -1,69 +0,0 @@ -/**************************************************************************** -** -** 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. -** -****************************************************************************/ - -#pragma once - -#include "clangbackendcommunicator.h" -#include "clangutils.h" - -#include - -namespace ClangCodeModel { -namespace Internal { - -enum class CompletionType { FunctionHint, Other }; - -class ClangCompletionAssistInterface: public TextEditor::AssistInterface -{ -public: - ClangCompletionAssistInterface(BackendCommunicator &communicator, - CompletionType type, - const TextEditor::TextEditorWidget *textEditorWidget, - int position, - const Utils::FilePath &fileName, - TextEditor::AssistReason reason, - const ProjectExplorer::HeaderPaths &headerPaths, - const CPlusPlus::LanguageFeatures &features); - - BackendCommunicator &communicator() const; - CompletionType type() const { return m_type; } - bool objcEnabled() const; - const ProjectExplorer::HeaderPaths &headerPaths() const; - CPlusPlus::LanguageFeatures languageFeatures() const; - const TextEditor::TextEditorWidget *textEditorWidget() const; - - void setHeaderPaths(const ProjectExplorer::HeaderPaths &headerPaths); // For tests - -private: - BackendCommunicator &m_communicator; - const CompletionType m_type; - QStringList m_options; - ProjectExplorer::HeaderPaths m_headerPaths; - CPlusPlus::LanguageFeatures m_languageFeatures; - const TextEditor::TextEditorWidget *m_textEditorWidget; -}; - -} // namespace Internal -} // namespace ClangCodeModel diff --git a/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp b/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp deleted file mode 100644 index db70275eade..00000000000 --- a/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp +++ /dev/null @@ -1,718 +0,0 @@ -/**************************************************************************** -** -** 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 "clangassistproposalitem.h" - -#include "clangactivationsequenceprocessor.h" -#include "clangassistproposalmodel.h" -#include "clangcompletionassistprocessor.h" -#include "clangcompletioncontextanalyzer.h" -#include "clangfixitoperation.h" -#include "clangfunctionhintmodel.h" -#include "clangcompletionchunkstotextconverter.h" -#include "clangpreprocessorassistproposalitem.h" - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -namespace ClangCodeModel { -namespace Internal { - -using ClangBackEnd::CodeCompletion; -using TextEditor::AssistProposalItemInterface; - -static void addAssistProposalItem(QList &items, - const CodeCompletion &codeCompletion, - const QString &name) -{ - auto item = new ClangAssistProposalItem; - items.push_back(item); - - item->setText(name); - item->setOrder(int(codeCompletion.priority)); - item->appendCodeCompletion(codeCompletion); -} - -// Add the next CXXMethod or CXXConstructor which is the overload for another existing item. -static void addFunctionOverloadAssistProposalItem(QList &items, - AssistProposalItemInterface *sameItem, - const ClangCompletionAssistInterface *interface, - const CodeCompletion &codeCompletion, - const QString &name) -{ - auto *item = static_cast(sameItem); - item->setHasOverloadsWithParameters(codeCompletion.hasParameters); - if (codeCompletion.completionKind == CodeCompletion::ConstructorCompletionKind) { - // It's the constructor, currently constructor definitions do not lead here. - // CLANG-UPGRADE-CHECK: Can we get here with constructor definition? - item->appendCodeCompletion(codeCompletion); - return; - } - - QTextCursor cursor = interface->textEditorWidget()->textCursor(); - cursor.setPosition(interface->position()); - cursor.movePosition(QTextCursor::StartOfWord); - - const ClangBackEnd::CodeCompletionChunk resultType = codeCompletion.chunks.first(); - if (matchPreviousWord(*interface->textEditorWidget(), cursor, resultType.text.toString())) { - // Function definition completion - do not merge completions together. - addAssistProposalItem(items, codeCompletion, name); - } else { - item->appendCodeCompletion(codeCompletion); - } -} - -// Check if they are both CXXMethod or CXXConstructor. -static bool isTheSameFunctionOverload(const CodeCompletion &completion, - const QString &name, - ClangAssistProposalItem *lastItem) -{ - return completion.completionKind == lastItem->firstCodeCompletion().completionKind - && lastItem->text() == name; -} - -QList ClangCompletionAssistProcessor::toAssistProposalItems( - const CodeCompletions &completions) const -{ - // TODO: Handle Qt4's SIGNAL/SLOT - // Possibly check for m_completionOperator == T_SIGNAL - // Possibly check for codeCompletion.completionKind == CodeCompletion::SignalCompletionKind - - QList items; - items.reserve(completions.size()); - - // If there are signals among the candidates, we employ the built-in code model to find out - // whether the cursor was on the second argument of a (dis)connect() call. - // If so, we offer only signals, as nothing else makes sense in that context. - bool considerOnlySignals = false; - if (m_position != -1 && Utils::anyOf(completions, [](const CodeCompletion &c) { - return c.completionKind == CodeCompletion::SignalCompletionKind; - })) { - considerOnlySignals = CppEditor::CppModelManager::instance() - ->positionRequiresSignal(m_interface->filePath().toString(), m_content, m_position); - } - for (const CodeCompletion &codeCompletion : completions) { - if (codeCompletion.text.isEmpty()) - continue; // It's an OverloadCandidate which has text but no typedText. - - if (considerOnlySignals - && codeCompletion.completionKind != CodeCompletion::ClassCompletionKind - && codeCompletion.completionKind != CodeCompletion::NamespaceCompletionKind - && codeCompletion.completionKind != CodeCompletion::SignalCompletionKind) { - continue; - } - - // Don't offer symbols that are not accessible here. - if (codeCompletion.availability == CodeCompletion::NotAvailable - || codeCompletion.availability == CodeCompletion::NotAccessible) { - continue; - } - - const QString name = codeCompletion.completionKind == CodeCompletion::KeywordCompletionKind - ? CompletionChunksToTextConverter::convertToName(codeCompletion.chunks) - : codeCompletion.text.toString(); - - if (items.empty()) { - addAssistProposalItem(items, codeCompletion, name); - } else { - auto *lastItem = static_cast(items.last()); - if (isTheSameFunctionOverload(codeCompletion, name, lastItem)) { - addFunctionOverloadAssistProposalItem(items, items.back(), m_interface.data(), - codeCompletion, name); - } else { - addAssistProposalItem(items, codeCompletion, name); - } - } - } - - return items; -} - -using namespace CPlusPlus; -using namespace TextEditor; - -ClangCompletionAssistProcessor::ClangCompletionAssistProcessor() - : CppCompletionAssistProcessor(100) - , m_completionOperator(T_EOF_SYMBOL) -{ -} - -ClangCompletionAssistProcessor::~ClangCompletionAssistProcessor() = default; - -IAssistProposal *ClangCompletionAssistProcessor::perform(const AssistInterface *interface) -{ - m_interface.reset(static_cast(interface)); - - if (interface->reason() != ExplicitlyInvoked && !accepts()) { - m_requestSent = false; - return nullptr; - } - - return startCompletionHelper(); // == 0 if results are calculated asynchronously -} - -// All completions require fix-it, apply this fix-it now. -CodeCompletions ClangCompletionAssistProcessor::applyCompletionFixIt(const CodeCompletions &completions) -{ - // CLANG-UPGRADE-CHECK: Currently we rely on fact that there are only 2 possible fix-it types: - // 'dot to arrow' and 'arrow to dot' and they can't appear for the same item. - // However if we get multiple options which trigger for the same code we need to improve this - // algorithm. Check comments to FixIts field of CodeCompletionResult and which fix-its are used - // to construct results in SemaCodeComplete.cpp. - const CodeCompletion &completion = completions.front(); - const ClangBackEnd::FixItContainer &fixIt = completion.requiredFixIts.front(); - - ClangFixItOperation fixItOperation(Utf8String(), completion.requiredFixIts); - fixItOperation.perform(); - - const int fixItLength = fixIt.range.end.column - fixIt.range.start.column; - const QString fixItText = fixIt.text.toString(); - m_positionForProposal += fixItText.length() - fixItLength; - - CodeCompletions completionsWithoutFixIts; - completionsWithoutFixIts.reserve(completions.size()); - for (const CodeCompletion &completion : completions) { - CodeCompletion completionCopy = completion; - completionCopy.requiredFixIts.clear(); - completionsWithoutFixIts.push_back(completionCopy); - } - - return completionsWithoutFixIts; -} - -void ClangCompletionAssistProcessor::handleAvailableCompletions(const CodeCompletions &completions) -{ - QTC_CHECK(m_completions.isEmpty()); - - if (m_sentRequestType == FunctionHintCompletion && !completions.isEmpty()) { - const CodeCompletion &firstCompletion = completions.front(); - if (firstCompletion.completionKind == CodeCompletion::FunctionOverloadCompletionKind) { - setAsyncProposalAvailable(createFunctionHintProposal(completions)); - return; - } - - if (!m_fallbackToNormalCompletion) { - // We must report back to the code assistant under all circumstances - setAsyncProposalAvailable(nullptr); - return; - } - // else: Proceed with a normal completion in case: - // 1) it was not a function call, but e.g. a function declaration like "void f(" - // 2) '{' meant not a constructor call. - } - - //m_sentRequestType == NormalCompletion or function signatures were empty - - // Completions are sorted the way that all items with fix-its come after all items without them - // therefore it's enough to check only the first one. - if (!completions.isEmpty() && !completions.front().requiredFixIts.isEmpty()) - m_completions = toAssistProposalItems(applyCompletionFixIt(completions)); - else - m_completions = toAssistProposalItems(completions); - - if (m_addSnippets && !m_completions.isEmpty()) - addSnippets(); - - setAsyncProposalAvailable(createProposal()); -} - -const TextEditorWidget *ClangCompletionAssistProcessor::textEditorWidget() const -{ - return m_interface->textEditorWidget(); -} - -/// Seach backwards in the document starting from pos to find the first opening -/// parenthesis. Nested parenthesis are skipped. -static int findOpenParen(QTextDocument *document, int start) -{ - unsigned parenCount = 1; - for (int position = start; position >= 0; --position) { - const QChar ch = document->characterAt(position); - if (ch == QLatin1Char('(')) { - --parenCount; - if (parenCount == 0) - return position; - } else if (ch == QLatin1Char(')')) { - ++parenCount; - } - } - return -1; -} - -static QByteArray modifyInput(QTextDocument *doc, int endOfExpression) { - int comma = endOfExpression; - while (comma > 0) { - const QChar ch = doc->characterAt(comma); - if (ch == QLatin1Char(',')) - break; - if (ch == QLatin1Char(';') || ch == QLatin1Char('{') || ch == QLatin1Char('}')) { - // Safety net: we don't seem to have "connect(pointer, SIGNAL(" as - // input, so stop searching. - comma = -1; - break; - } - --comma; - } - if (comma < 0) - return QByteArray(); - const int openBrace = findOpenParen(doc, comma); - if (openBrace < 0) - return QByteArray(); - - QByteArray modifiedInput = doc->toPlainText().toUtf8(); - const int len = endOfExpression - comma; - QByteArray replacement(len - 4, ' '); - replacement.append(")->"); - modifiedInput.replace(comma, len, replacement); - modifiedInput.insert(openBrace, '('); - return modifiedInput; -} - -static QChar lastPrecedingNonWhitespaceChar(const ClangCompletionAssistInterface *interface) -{ - int pos = interface->position(); - while (pos >= 0 && interface->characterAt(pos).isSpace()) - --pos; - return pos >= 0 ? interface->characterAt(pos) : QChar::Null; -} - -IAssistProposal *ClangCompletionAssistProcessor::startCompletionHelper() -{ - ClangCompletionContextAnalyzer analyzer(m_interface.data(), m_interface->languageFeatures()); - analyzer.analyze(); - m_completionOperator = analyzer.completionOperator(); - m_positionForProposal = analyzer.positionForProposal(); - m_addSnippets = analyzer.addSnippets(); - - QByteArray modifiedFileContent; - - const ClangCompletionContextAnalyzer::CompletionAction action = analyzer.completionAction(); - switch (action) { - case ClangCompletionContextAnalyzer::CompleteDoxygenKeyword: - if (completeDoxygenKeywords()) - return createProposal(); - break; - case ClangCompletionContextAnalyzer::CompleteIncludePath: - m_completions = completeInclude(analyzer.positionEndOfExpression(), m_completionOperator, - m_interface.data(), m_interface->headerPaths()); - if (!m_completions.isEmpty()) - return createProposal(); - break; - case ClangCompletionContextAnalyzer::CompletePreprocessorDirective: - if (completePreprocessorDirectives()) - return createProposal(); - break; - case ClangCompletionContextAnalyzer::CompleteSignal: - case ClangCompletionContextAnalyzer::CompleteSlot: - modifiedFileContent = modifyInput(m_interface->textDocument(), - analyzer.positionEndOfExpression()); - Q_FALLTHROUGH(); - case ClangCompletionContextAnalyzer::PassThroughToLibClang: { - m_sentRequestType = NormalCompletion; - m_requestSent = sendCompletionRequest(analyzer.positionForClang(), - modifiedFileContent); - break; - } - case ClangCompletionContextAnalyzer::PassThroughToLibClangAfterLeftParen: { - m_sentRequestType = FunctionHintCompletion; - if (lastPrecedingNonWhitespaceChar(m_interface.data()) == ',') - m_fallbackToNormalCompletion = false; - m_requestSent = sendCompletionRequest(analyzer.positionForClang(), QByteArray(), - analyzer.functionNameStart()); - break; - } - case ClangCompletionContextAnalyzer::CompleteNone: - default: - break; - } - - return nullptr; -} - -int ClangCompletionAssistProcessor::startOfOperator(int positionInDocument, - unsigned *kind, - bool wantFunctionCall) const -{ - auto activationSequence = m_interface->textAt(positionInDocument - 3, 3); - ActivationSequenceProcessor activationSequenceProcessor(activationSequence, - positionInDocument, - wantFunctionCall); - - *kind = activationSequenceProcessor.completionKind(); - int start = activationSequenceProcessor.operatorStartPosition(); - - CppCompletionAssistProcessor::startOfOperator(m_interface->textDocument(), - positionInDocument, - kind, - start, - m_interface->languageFeatures()); - - return start; -} - -int ClangCompletionAssistProcessor::findStartOfName(int pos) const -{ - if (pos == -1) - pos = m_interface->position(); - QChar chr; - - // Skip to the start of a name - do { - chr = m_interface->characterAt(--pos); - } while (chr.isLetterOrNumber() || chr == QLatin1Char('_')); - - return pos + 1; -} - -bool ClangCompletionAssistProcessor::accepts() const -{ - const int pos = m_interface->position(); - unsigned token = T_EOF_SYMBOL; - - const int start = startOfOperator(pos, &token, /*want function call=*/ true); - if (start != pos) { - if (token == T_POUND) { - const int column = pos - m_interface->textDocument()->findBlock(start).position(); - if (column != 1) - return false; - } - - return true; - } else { - // Trigger completion after n characters of a name have been typed, when not editing an existing name - QChar characterUnderCursor = m_interface->characterAt(pos); - if (!characterUnderCursor.isLetterOrNumber() && characterUnderCursor != QLatin1Char('_')) { - const int startOfName = findStartOfName(pos); - if (pos - startOfName >= TextEditorSettings::completionSettings().m_characterThreshold) { - const QChar firstCharacter = m_interface->characterAt(startOfName); - if (firstCharacter.isLetter() || firstCharacter == QLatin1Char('_')) { - return !CppEditor::isInCommentOrString(m_interface.data(), - m_interface->languageFeatures()); - } - } - } - } - - return false; -} - -/** - * @brief Creates completion proposals for #include and given cursor - * @param position - cursor placed after opening bracked or quote - * @param completionOperator - the type of token - * @param interface - relevant document data - * @param headerPaths - the include paths - * @return the list of completion items - */ -QList ClangCompletionAssistProcessor::completeInclude( - int position, unsigned completionOperator, const TextEditor::AssistInterface *interface, - const ProjectExplorer::HeaderPaths &headerPaths) -{ - QTextCursor cursor(interface->textDocument()); - cursor.setPosition(position); - QString directoryPrefix; - if (completionOperator == T_SLASH) { - QTextCursor c = cursor; - c.movePosition(QTextCursor::StartOfLine, QTextCursor::KeepAnchor); - QString sel = c.selectedText(); - int startCharPos = sel.indexOf(QLatin1Char('"')); - if (startCharPos == -1) { - startCharPos = sel.indexOf(QLatin1Char('<')); - completionOperator = T_ANGLE_STRING_LITERAL; - } else { - completionOperator = T_STRING_LITERAL; - } - if (startCharPos != -1) - directoryPrefix = sel.mid(startCharPos + 1, sel.length() - 1); - } - - // Make completion for all relevant includes - ProjectExplorer::HeaderPaths allHeaderPaths = headerPaths; - const auto currentFilePath = ProjectExplorer::HeaderPath::makeUser( - interface->filePath().toFileInfo().path()); - if (!allHeaderPaths.contains(currentFilePath)) - allHeaderPaths.append(currentFilePath); - - const ::Utils::MimeType mimeType = ::Utils::mimeTypeForName("text/x-c++hdr"); - const QStringList suffixes = mimeType.suffixes(); - - QList completions; - foreach (const ProjectExplorer::HeaderPath &headerPath, allHeaderPaths) { - QString realPath = headerPath.path; - if (!directoryPrefix.isEmpty()) { - realPath += QLatin1Char('/'); - realPath += directoryPrefix; - if (headerPath.type == ProjectExplorer::HeaderPathType::Framework) - realPath += QLatin1String(".framework/Headers"); - } - completions << completeIncludePath(realPath, suffixes, completionOperator); - } - - QList> completionsForSorting; - for (AssistProposalItemInterface * const item : qAsConst(completions)) { - QString s = item->text(); - s.replace('/', QChar(0)); // The dir separator should compare less than anything else. - completionsForSorting << qMakePair(item, s); - } - Utils::sort(completionsForSorting, [](const auto &left, const auto &right) { - return left.second < right.second; - }); - for (int i = 0; i < completionsForSorting.count(); ++i) - completions[i] = completionsForSorting[i].first; - - return completions; -} - -/** - * @brief Finds #include completion proposals using given include path - * @param realPath - one of directories where compiler searches includes - * @param suffixes - file suffixes for C/C++ header files - * @return a list of matching completion items - */ -QList ClangCompletionAssistProcessor::completeIncludePath( - const QString &realPath, const QStringList &suffixes, unsigned completionOperator) -{ - QList completions; - QDirIterator i(realPath, QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot); - //: Parent folder for proposed #include completion - const QString hint = tr("Location: %1").arg(QDir::toNativeSeparators(QDir::cleanPath(realPath))); - while (i.hasNext()) { - const QString fileName = i.next(); - const QFileInfo fileInfo = i.fileInfo(); - const QString suffix = fileInfo.suffix(); - if (suffix.isEmpty() || suffixes.contains(suffix)) { - QString text = fileName.mid(realPath.length() + 1); - if (fileInfo.isDir()) - text += QLatin1Char('/'); - - auto *item = new ClangPreprocessorAssistProposalItem; - item->setText(text); - item->setDetail(hint); - item->setIcon(CPlusPlus::Icons::keywordIcon()); - item->setCompletionOperator(completionOperator); - completions.append(item); - } - } - return completions; -} - -bool ClangCompletionAssistProcessor::completePreprocessorDirectives() -{ - foreach (const QString &preprocessorCompletion, preprocessorCompletions()) - addCompletionItem(preprocessorCompletion, - Utils::CodeModelIcon::iconForType(Utils::CodeModelIcon::Macro)); - - if (m_interface->objcEnabled()) - addCompletionItem(QLatin1String("import"), - Utils::CodeModelIcon::iconForType(Utils::CodeModelIcon::Macro)); - - return !m_completions.isEmpty(); -} - -bool ClangCompletionAssistProcessor::completeDoxygenKeywords() -{ - for (int i = 1; i < CppEditor::T_DOXY_LAST_TAG; ++i) - addCompletionItem(QString::fromLatin1(CppEditor::doxygenTagSpell(i)), CPlusPlus::Icons::keywordIcon()); - return !m_completions.isEmpty(); -} - -void ClangCompletionAssistProcessor::addCompletionItem(const QString &text, - const QIcon &icon, - int order) -{ - auto *item = new ClangPreprocessorAssistProposalItem; - item->setText(text); - item->setIcon(icon); - item->setOrder(order); - item->setCompletionOperator(m_completionOperator); - m_completions.append(item); -} - -ClangCompletionAssistProcessor::UnsavedFileContentInfo -ClangCompletionAssistProcessor::unsavedFileContent(const QByteArray &customFileContent) const -{ - const bool hasCustomModification = !customFileContent.isEmpty(); - - UnsavedFileContentInfo info; - info.isDocumentModified = hasCustomModification || m_interface->textDocument()->isModified(); - info.unsavedContent = hasCustomModification - ? customFileContent - : m_interface->textDocument()->toPlainText().toUtf8(); - return info; -} - -void ClangCompletionAssistProcessor::sendFileContent(const QByteArray &customFileContent) -{ - // TODO: Revert custom modification after the completions - const UnsavedFileContentInfo info = unsavedFileContent(customFileContent); - - BackendCommunicator &communicator = m_interface->communicator(); - communicator.documentsChanged({{m_interface->filePath().toString(), - Utf8String::fromByteArray(info.unsavedContent), - info.isDocumentModified, - uint(m_interface->textDocument()->revision())}}); -} -namespace { -bool shouldSendDocumentForCompletion(const QString &filePath, - int completionPosition) -{ - CppEditor::CppEditorDocumentHandle *document = cppDocument(filePath); - - if (document) { - auto &sendTracker = document->sendTracker(); - return sendTracker.shouldSendRevisionWithCompletionPosition(int(document->revision()), - completionPosition); - } - - return true; -} - -bool shouldSendCodeCompletion(const QString &filePath, - int completionPosition) -{ - CppEditor::CppEditorDocumentHandle *document = cppDocument(filePath); - - if (document) { - auto &sendTracker = document->sendTracker(); - return sendTracker.shouldSendCompletion(completionPosition); - } - - return true; -} - -void setLastDocumentRevision(const QString &filePath) -{ - CppEditor::CppEditorDocumentHandle *document = cppDocument(filePath); - - if (document) - document->sendTracker().setLastSentRevision(int(document->revision())); -} - -void setLastCompletionPosition(const QString &filePath, - int completionPosition) -{ - CppEditor::CppEditorDocumentHandle *document = cppDocument(filePath); - - if (document) - document->sendTracker().setLastCompletionPosition(completionPosition); -} - -} - -ClangCompletionAssistProcessor::Position -ClangCompletionAssistProcessor::extractLineColumn(int position) -{ - if (position < 0) - return {-1, -1}; - - int line = -1, column = -1; - Utils::Text::convertPosition(m_interface->textDocument(), position, &line, &column); - - column = clangColumn(m_interface->textDocument()->findBlock(position), column); - return {line, column}; -} - -bool ClangCompletionAssistProcessor::sendCompletionRequest(int position, - const QByteArray &customFileContent, - int functionNameStartPosition) -{ - const QString filePath = m_interface->filePath().toString(); - - auto &communicator = m_interface->communicator(); - - if (shouldSendCodeCompletion(filePath, position) || communicator.isNotWaitingForCompletion()) { - if (shouldSendDocumentForCompletion(filePath, position)) { - sendFileContent(customFileContent); - setLastDocumentRevision(filePath); - } - - const Position cursorPosition = extractLineColumn(position); - const Position functionNameStart = extractLineColumn(functionNameStartPosition); - communicator.requestCompletions(this, - filePath, - uint(cursorPosition.line), - uint(cursorPosition.column), - functionNameStart.line, - functionNameStart.column); - setLastCompletionPosition(filePath, position); - if (m_sentRequestType == NormalCompletion) { - if (!customFileContent.isEmpty()) - m_content = customFileContent; - else if (const CppEditor::CppEditorDocumentHandle * const doc = cppDocument(filePath)) - m_content = doc->contents(); - m_position = position; - } - return true; - } - - return false; -} - -TextEditor::IAssistProposal *ClangCompletionAssistProcessor::createProposal() -{ - m_requestSent = false; - TextEditor::GenericProposalModelPtr model(new ClangAssistProposalModel()); - model->loadContent(m_completions); - return new GenericProposal(m_positionForProposal, model); -} - -IAssistProposal *ClangCompletionAssistProcessor::createFunctionHintProposal( - const ClangBackEnd::CodeCompletions &completions) -{ - m_requestSent = false; - TextEditor::FunctionHintProposalModelPtr model(new ClangFunctionHintModel(completions)); - return new FunctionHintProposal(m_positionForProposal, model); -} - -void ClangCompletionAssistProcessor::cancel() -{ - m_interface->communicator().cancelCompletions(this); -} - -} // namespace Internal -} // namespace ClangCodeModel diff --git a/src/plugins/clangcodemodel/clangcompletionassistprocessor.h b/src/plugins/clangcodemodel/clangcompletionassistprocessor.h deleted file mode 100644 index 1d67344cc86..00000000000 --- a/src/plugins/clangcodemodel/clangcompletionassistprocessor.h +++ /dev/null @@ -1,117 +0,0 @@ -/**************************************************************************** -** -** 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. -** -****************************************************************************/ - -#pragma once - -#include "clangcompletionassistinterface.h" - -#include - -#include - -#include -#include - -namespace TextEditor { -class AssistInterface; -class AssistProposalItemInterface; -} - -namespace ClangCodeModel { -namespace Internal { - -using ClangBackEnd::CodeCompletions; -using ClangBackEnd::CompletionCorrection; - -class ClangCompletionAssistProcessor : public CppEditor::CppCompletionAssistProcessor -{ - Q_DECLARE_TR_FUNCTIONS(ClangCodeModel::Internal::ClangCompletionAssistProcessor) - -public: - ClangCompletionAssistProcessor(); - ~ClangCompletionAssistProcessor() override; - - static QList completeInclude( - int position, unsigned completionOperator, - const TextEditor::AssistInterface *interface, - const ProjectExplorer::HeaderPaths &headerPaths); - - TextEditor::IAssistProposal *perform(const TextEditor::AssistInterface *interface) override; - - void handleAvailableCompletions(const CodeCompletions &completions); - bool running() final { return m_requestSent; } - - const TextEditor::TextEditorWidget *textEditorWidget() const; - -private: - void cancel() override; - TextEditor::IAssistProposal *startCompletionHelper(); - int startOfOperator(int pos, unsigned *kind, bool wantFunctionCall) const; - int findStartOfName(int pos = -1) const; - bool accepts() const; - - TextEditor::IAssistProposal *createProposal(); - TextEditor::IAssistProposal *createFunctionHintProposal( - const CodeCompletions &completions); - QList toAssistProposalItems( - const CodeCompletions &completions) const; - static QList completeIncludePath( - const QString &realPath, const QStringList &suffixes, unsigned completionOperator); - bool completePreprocessorDirectives(); - bool completeDoxygenKeywords(); - void addCompletionItem(const QString &text, - const QIcon &icon = QIcon(), - int order = 0); - - struct UnsavedFileContentInfo { - QByteArray unsavedContent; - bool isDocumentModified = false; - }; - UnsavedFileContentInfo unsavedFileContent(const QByteArray &customFileContent) const; - - void sendFileContent(const QByteArray &customFileContent); - bool sendCompletionRequest(int position, - const QByteArray &customFileContent, - int functionNameStartPosition = -1); - - CodeCompletions applyCompletionFixIt(const CodeCompletions &completions); - -private: - struct Position { int line; int column; }; - Position extractLineColumn(int position); - - QScopedPointer m_interface; - unsigned m_completionOperator; - enum CompletionRequestType { NormalCompletion, FunctionHintCompletion }; - CompletionRequestType m_sentRequestType = NormalCompletion; - int m_position = -1; - QByteArray m_content; - bool m_requestSent = false; - bool m_addSnippets = false; // For type == Type::NormalCompletion - bool m_fallbackToNormalCompletion = true; -}; - -} // namespace Internal -} // namespace ClangCodeModel diff --git a/src/plugins/clangcodemodel/clangcompletionassistprovider.cpp b/src/plugins/clangcodemodel/clangcompletionassistprovider.cpp deleted file mode 100644 index c3c752f9569..00000000000 --- a/src/plugins/clangcodemodel/clangcompletionassistprovider.cpp +++ /dev/null @@ -1,87 +0,0 @@ -/**************************************************************************** -** -** 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 "clangcompletionassistprovider.h" - -#include "clangcompletionassistprocessor.h" -#include "clangeditordocumentprocessor.h" -#include "clangutils.h" - -#include -#include -#include - -#include -#include -#include -#include - -#include - -namespace ClangCodeModel { -namespace Internal { - -ClangCompletionAssistProvider::ClangCompletionAssistProvider(BackendCommunicator &communicator, - CompletionType type) - : m_communicator(communicator), m_type(type) -{ -} - -TextEditor::IAssistProvider::RunType ClangCompletionAssistProvider::runType() const -{ - return Asynchronous; -} - -TextEditor::IAssistProcessor *ClangCompletionAssistProvider::createProcessor( - const TextEditor::AssistInterface *) const -{ - return new ClangCompletionAssistProcessor; -} - -TextEditor::AssistInterface *ClangCompletionAssistProvider::createAssistInterface( - const Utils::FilePath &filePath, - const TextEditor::TextEditorWidget *textEditorWidget, - const CPlusPlus::LanguageFeatures & /*languageFeatures*/, - int position, - TextEditor::AssistReason reason) const -{ - const CppEditor::ProjectPart::ConstPtr projectPart = projectPartForFileBasedOnProcessor( - filePath.toString()); - if (projectPart) { - return new ClangCompletionAssistInterface(m_communicator, - m_type, - textEditorWidget, - position, - filePath, - reason, - projectPart->headerPaths, - projectPart->languageFeatures); - } - - return nullptr; -} - -} // namespace Internal -} // namespace ClangCodeModel diff --git a/src/plugins/clangcodemodel/clangcompletionassistprovider.h b/src/plugins/clangcodemodel/clangcompletionassistprovider.h deleted file mode 100644 index c1bb5b6b87c..00000000000 --- a/src/plugins/clangcodemodel/clangcompletionassistprovider.h +++ /dev/null @@ -1,61 +0,0 @@ -/**************************************************************************** -** -** 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. -** -****************************************************************************/ - -#pragma once - -#include "clangbackendcommunicator.h" -#include "clangcompletionassistinterface.h" - -#include - -#include - -namespace ClangCodeModel { -namespace Internal { - -class ClangCompletionAssistProvider : public CppEditor::CppCompletionAssistProvider -{ - Q_OBJECT - -public: - ClangCompletionAssistProvider(BackendCommunicator &communicator, CompletionType type); - - IAssistProvider::RunType runType() const override; - - TextEditor::IAssistProcessor *createProcessor(const TextEditor::AssistInterface *) const override; - TextEditor::AssistInterface *createAssistInterface( - const Utils::FilePath &filePath, - const TextEditor::TextEditorWidget *textEditorWidget, - const CPlusPlus::LanguageFeatures &languageFeatures, - int position, - TextEditor::AssistReason reason) const override; - -private: - BackendCommunicator &m_communicator; - CompletionType m_type; -}; - -} // namespace Internal -} // namespace ClangCodeModel diff --git a/src/plugins/clangcodemodel/clangcompletionchunkstotextconverter.cpp b/src/plugins/clangcodemodel/clangcompletionchunkstotextconverter.cpp deleted file mode 100644 index ad5ee50476f..00000000000 --- a/src/plugins/clangcodemodel/clangcompletionchunkstotextconverter.cpp +++ /dev/null @@ -1,366 +0,0 @@ -/**************************************************************************** -** -** 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 "clangcompletionchunkstotextconverter.h" - -#include - -#include -#include - -namespace ClangCodeModel { -namespace Internal { - -void CompletionChunksToTextConverter::parseChunks( - const ClangBackEnd::CodeCompletionChunks &codeCompletionChunks) -{ - m_text.clear(); - m_placeholderPositions.clear(); - - m_codeCompletionChunks = codeCompletionChunks; - - addExtraVerticalSpaceBetweenBraces(); - - std::for_each(m_codeCompletionChunks.cbegin(), - m_codeCompletionChunks.cend(), - [this] (const ClangBackEnd::CodeCompletionChunk &chunk) - { - parseDependentOnTheOptionalState(chunk); - m_previousCodeCompletionChunk = chunk; - }); -} - -void CompletionChunksToTextConverter::setAddPlaceHolderText(bool addPlaceHolderText) -{ - m_addPlaceHolderText = addPlaceHolderText; -} - -void CompletionChunksToTextConverter::setAddPlaceHolderPositions(bool addPlaceHolderPositions) -{ - m_addPlaceHolderPositions = addPlaceHolderPositions; -} - -void CompletionChunksToTextConverter::setAddResultType(bool addResultType) -{ - m_addResultType = addResultType; -} - -void CompletionChunksToTextConverter::setAddSpaces(bool addSpaces) -{ - m_addSpaces = addSpaces; -} - -void CompletionChunksToTextConverter::setHonorVerticalSpace(bool honor) -{ - m_honorVerticalSpace = honor; -} - -void CompletionChunksToTextConverter::setAddExtraVerticalSpaceBetweenBraces( - bool addExtraVerticalSpaceBetweenBraces) -{ - m_addExtraVerticalSpaceBetweenBraces = addExtraVerticalSpaceBetweenBraces; -} - -void CompletionChunksToTextConverter::setEmphasizeOptional(bool emphasizeOptional) -{ - m_emphasizeOptional = emphasizeOptional; -} - -void CompletionChunksToTextConverter::setAddOptional(bool addOptional) -{ - m_addOptional = addOptional; -} - -void CompletionChunksToTextConverter::setPlaceHolderToEmphasize(int placeHolderNumber) -{ - m_placeHolderPositionToEmphasize = placeHolderNumber; -} - -void CompletionChunksToTextConverter::setCompletionKind(const ClangBackEnd::CodeCompletion::Kind kind) -{ - m_codeCompletionKind = kind; -} - -void CompletionChunksToTextConverter::setupForKeywords() -{ - setAddPlaceHolderPositions(true); - setAddSpaces(true); - setAddExtraVerticalSpaceBetweenBraces(true); -} - -const QString &CompletionChunksToTextConverter::text() const -{ - return m_text; -} - -const std::vector &CompletionChunksToTextConverter::placeholderPositions() const -{ - return m_placeholderPositions; -} - -bool CompletionChunksToTextConverter::hasPlaceholderPositions() const -{ - return m_placeholderPositions.size() > 0; -} - -QString CompletionChunksToTextConverter::convertToFunctionSignatureWithHtml( - const ClangBackEnd::CodeCompletionChunks &codeCompletionChunks, - ClangBackEnd::CodeCompletion::Kind codeCompletionKind, - int parameterToEmphasize) -{ - CompletionChunksToTextConverter converter; - converter.setAddPlaceHolderText(true); - converter.setAddResultType(true); - - converter.setTextFormat(TextFormat::Html); - converter.setAddOptional(true); - converter.setEmphasizeOptional(true); - - converter.setAddPlaceHolderPositions(true); - converter.setPlaceHolderToEmphasize(parameterToEmphasize); - converter.setCompletionKind(codeCompletionKind); - - converter.parseChunks(codeCompletionChunks); - - return converter.text(); -} - -QString CompletionChunksToTextConverter::convertToName( - const ClangBackEnd::CodeCompletionChunks &codeCompletionChunks) -{ - CompletionChunksToTextConverter converter; - - converter.setHonorVerticalSpace(false); - - converter.parseChunks(codeCompletionChunks); - - return converter.text(); -} - -QString CompletionChunksToTextConverter::convertToToolTipWithHtml( - const ClangBackEnd::CodeCompletionChunks &codeCompletionChunks, - ClangBackEnd::CodeCompletion::Kind codeCompletionKind) -{ - CompletionChunksToTextConverter converter; - converter.setAddPlaceHolderText(true); - converter.setAddSpaces(true); - converter.setAddExtraVerticalSpaceBetweenBraces(true); - converter.setAddOptional(true); - converter.setTextFormat(TextFormat::Html); - converter.setEmphasizeOptional(true); - converter.setAddResultType(true); - converter.setCompletionKind(codeCompletionKind); - - converter.parseChunks(codeCompletionChunks); - - return converter.text(); -} - -void CompletionChunksToTextConverter::parse( - const ClangBackEnd::CodeCompletionChunk &codeCompletionChunk) -{ - using ClangBackEnd::CodeCompletionChunk; - - switch (codeCompletionChunk.kind) { - case CodeCompletionChunk::ResultType: parseResultType(codeCompletionChunk.text); break; - // Do not rely on CurrentParameter because it might be wrong for - // invalid code. Instead, handle it as PlaceHolder. - case CodeCompletionChunk::CurrentParameter: - case CodeCompletionChunk::Placeholder: - parsePlaceHolder(codeCompletionChunk); break; - case CodeCompletionChunk::LeftParen: parseLeftParen(codeCompletionChunk); break; - case CodeCompletionChunk::LeftBrace: parseLeftBrace(codeCompletionChunk); break; - case CodeCompletionChunk::VerticalSpace: - if (!m_honorVerticalSpace) - break; - Q_FALLTHROUGH(); - default: parseText(codeCompletionChunk.text); break; - } -} - -void CompletionChunksToTextConverter::parseDependentOnTheOptionalState( - const ClangBackEnd::CodeCompletionChunk &codeCompletionChunk) -{ - wrapInCursiveTagIfOptional(codeCompletionChunk); - - if (isNotOptionalOrAddOptionals(codeCompletionChunk)) - parse(codeCompletionChunk); -} - -void CompletionChunksToTextConverter::parseResultType(const Utf8String &resultTypeText) -{ - if (m_addResultType) - m_text += inDesiredTextFormat(resultTypeText) + QChar(QChar::Space); -} - -void CompletionChunksToTextConverter::parseText(const Utf8String &text) -{ - if (canAddSpace() - && m_previousCodeCompletionChunk.kind == ClangBackEnd::CodeCompletionChunk::RightBrace) { - m_text += QChar(QChar::Space); - } - - m_text += inDesiredTextFormat(text); -} - -void CompletionChunksToTextConverter::wrapInCursiveTagIfOptional( - const ClangBackEnd::CodeCompletionChunk &codeCompletionChunk) -{ - if (m_addOptional) { - if (m_emphasizeOptional && m_textFormat == TextFormat::Html) { - if (!m_previousCodeCompletionChunk.isOptional && codeCompletionChunk.isOptional) - m_text += QStringLiteral(""); - else if (m_previousCodeCompletionChunk.isOptional && !codeCompletionChunk.isOptional) - m_text += QStringLiteral(""); - } - } -} - -void CompletionChunksToTextConverter::parsePlaceHolder( - const ClangBackEnd::CodeCompletionChunk &codeCompletionChunk) -{ - if (m_addPlaceHolderText) { - appendText(inDesiredTextFormat(codeCompletionChunk.text), - emphasizeCurrentPlaceHolder()); - } - - if (m_addPlaceHolderPositions) - m_placeholderPositions.push_back(m_text.size()); -} - -void CompletionChunksToTextConverter::parseLeftParen( - const ClangBackEnd::CodeCompletionChunk &codeCompletionChunk) -{ - if (canAddSpace()) - m_text += QChar(QChar::Space); - m_text += codeCompletionChunk.text.toString(); -} - -void CompletionChunksToTextConverter::parseLeftBrace( - const ClangBackEnd::CodeCompletionChunk &codeCompletionChunk) -{ - if (canAddSpace()) - m_text += QChar(QChar::Space); - - m_text += codeCompletionChunk.text.toString(); -} - -void CompletionChunksToTextConverter::addExtraVerticalSpaceBetweenBraces() -{ - if (m_addExtraVerticalSpaceBetweenBraces) - addExtraVerticalSpaceBetweenBraces(m_codeCompletionChunks.begin()); -} - -void CompletionChunksToTextConverter::addExtraVerticalSpaceBetweenBraces( - const ClangBackEnd::CodeCompletionChunks::iterator &begin) -{ - using ClangBackEnd::CodeCompletionChunk; - - const auto leftBraceCompare = [] (const CodeCompletionChunk &chunk) { - return chunk.kind == CodeCompletionChunk::LeftBrace; - }; - - const auto rightBraceCompare = [] (const CodeCompletionChunk &chunk) { - return chunk.kind == CodeCompletionChunk::RightBrace; - }; - - const auto verticalSpaceCompare = [] (const CodeCompletionChunk &chunk) { - return chunk.kind == CodeCompletionChunk::VerticalSpace; - }; - - auto leftBrace = std::find_if(begin, m_codeCompletionChunks.end(), leftBraceCompare); - - if (leftBrace != m_codeCompletionChunks.end()) { - auto rightBrace = std::find_if(leftBrace, m_codeCompletionChunks.end(), rightBraceCompare); - - if (rightBrace != m_codeCompletionChunks.end()) { - auto verticalSpaceCount = std::count_if(leftBrace, rightBrace, verticalSpaceCompare); - - if (verticalSpaceCount <= 1) { - auto distance = std::distance(leftBrace, rightBrace); - CodeCompletionChunk verticalSpaceChunck(CodeCompletionChunk::VerticalSpace, - Utf8StringLiteral("\n")); - auto verticalSpace = m_codeCompletionChunks.insert(std::next(leftBrace), - verticalSpaceChunck); - std::advance(verticalSpace, distance); - rightBrace = verticalSpace; - } - - auto begin = std::next(rightBrace); - - if (begin != m_codeCompletionChunks.end()) - addExtraVerticalSpaceBetweenBraces(begin); - } - } -} - -QString CompletionChunksToTextConverter::inDesiredTextFormat(const Utf8String &text) const -{ - if (m_textFormat == TextFormat::Html) - return text.toString().toHtmlEscaped(); - else - return text.toString(); -} - -bool CompletionChunksToTextConverter::emphasizeCurrentPlaceHolder() const -{ - if (m_addPlaceHolderPositions) { - const uint currentPlaceHolderPosition = uint(m_placeholderPositions.size() + 1); - return uint(m_placeHolderPositionToEmphasize) == currentPlaceHolderPosition; - } - - return false; -} - -void CompletionChunksToTextConverter::setTextFormat(TextFormat textFormat) -{ - m_textFormat = textFormat; -} - -void CompletionChunksToTextConverter::appendText(const QString &text, bool boldFormat) -{ - if (boldFormat && m_textFormat == TextFormat::Html) - m_text += QStringLiteral("") + text + QStringLiteral(""); - else - m_text += text; -} - -bool CompletionChunksToTextConverter::canAddSpace() const -{ - return m_addSpaces - && m_previousCodeCompletionChunk.kind != ClangBackEnd::CodeCompletionChunk::HorizontalSpace - && m_previousCodeCompletionChunk.kind != ClangBackEnd::CodeCompletionChunk::RightAngle - && m_codeCompletionKind != ClangBackEnd::CodeCompletion::FunctionCompletionKind; -} - -bool CompletionChunksToTextConverter::isNotOptionalOrAddOptionals( - const ClangBackEnd::CodeCompletionChunk &codeCompletionChunk) const -{ - return !codeCompletionChunk.isOptional || m_addOptional; -} - -} // namespace Internal -} // namespace ClangCodeModel - diff --git a/src/plugins/clangcodemodel/clangcompletionchunkstotextconverter.h b/src/plugins/clangcodemodel/clangcompletionchunkstotextconverter.h deleted file mode 100644 index abb5609b0d3..00000000000 --- a/src/plugins/clangcodemodel/clangcompletionchunkstotextconverter.h +++ /dev/null @@ -1,114 +0,0 @@ -/**************************************************************************** -** -** 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. -** -****************************************************************************/ - -#pragma once - -#include - -#include - -#include - -#include - -namespace ClangCodeModel { -namespace Internal { - -class CompletionChunksToTextConverter -{ -public: - void parseChunks(const ClangBackEnd::CodeCompletionChunks &codeCompletionChunks); - - enum class TextFormat { - Plain, - Html - }; - void setTextFormat(TextFormat textFormat); - void setAddPlaceHolderText(bool addPlaceHolderText); - void setAddPlaceHolderPositions(bool addPlaceHolderPositions); - void setAddResultType(bool addResultType); - void setAddSpaces(bool addSpaces); - void setHonorVerticalSpace(bool honor); - void setAddExtraVerticalSpaceBetweenBraces(bool addExtraVerticalSpaceBetweenBraces); - void setEmphasizeOptional(bool emphasizeOptional); // Only for Html format - void setAddOptional(bool addOptional); - void setPlaceHolderToEmphasize(int placeHolderNumber); - void setCompletionKind(const ClangBackEnd::CodeCompletion::Kind kind); - - void setupForKeywords(); - - const QString &text() const; - const std::vector &placeholderPositions() const; - bool hasPlaceholderPositions() const; - - static QString convertToName(const ClangBackEnd::CodeCompletionChunks &codeCompletionChunks); - static QString convertToKeywords(const ClangBackEnd::CodeCompletionChunks &codeCompletionChunks); - static QString convertToToolTipWithHtml( - const ClangBackEnd::CodeCompletionChunks &codeCompletionChunks, - ClangBackEnd::CodeCompletion::Kind codeCompletionKind); - static QString convertToFunctionSignatureWithHtml( - const ClangBackEnd::CodeCompletionChunks &codeCompletionChunks, - ClangBackEnd::CodeCompletion::Kind codeCompletionKind, - int parameterToEmphasize = -1); - -private: - void parse(const ClangBackEnd::CodeCompletionChunk &codeCompletionChunk); - void parseDependentOnTheOptionalState(const ClangBackEnd::CodeCompletionChunk &codeCompletionChunk); - void parseResultType(const Utf8String &text); - void parseText(const Utf8String &text); - void wrapInCursiveTagIfOptional(const ClangBackEnd::CodeCompletionChunk &codeCompletionChunk); - void parsePlaceHolder(const ClangBackEnd::CodeCompletionChunk &codeCompletionChunk); - void parseLeftParen(const ClangBackEnd::CodeCompletionChunk &codeCompletionChunk); - void parseLeftBrace(const ClangBackEnd::CodeCompletionChunk &codeCompletionChunk); - void addExtraVerticalSpaceBetweenBraces(); - void addExtraVerticalSpaceBetweenBraces(const ClangBackEnd::CodeCompletionChunks::iterator &); - - QString inDesiredTextFormat(const Utf8String &text) const; - void appendText(const QString &text, bool boldFormat = false); // Boldness only in Html format - bool canAddSpace() const; - bool isNotOptionalOrAddOptionals(const ClangBackEnd::CodeCompletionChunk &codeCompletionChunk) const; - - bool emphasizeCurrentPlaceHolder() const; - -private: - std::vector m_placeholderPositions; - ClangBackEnd::CodeCompletionChunks m_codeCompletionChunks; - ClangBackEnd::CodeCompletionChunk m_previousCodeCompletionChunk; - QString m_text; - int m_placeHolderPositionToEmphasize = -1; - TextFormat m_textFormat = TextFormat::Plain; - ClangBackEnd::CodeCompletion::Kind m_codeCompletionKind = ClangBackEnd::CodeCompletion::Other; - bool m_addPlaceHolderText = false; - bool m_addPlaceHolderPositions = false; - bool m_addResultType = false; - bool m_addSpaces = false; - bool m_honorVerticalSpace = true; - bool m_addExtraVerticalSpaceBetweenBraces = false; - bool m_emphasizeOptional = false; - bool m_addOptional = false; -}; - -} // namespace Internal -} // namespace ClangCodeModel diff --git a/src/plugins/clangcodemodel/clangcompletioncontextanalyzer.cpp b/src/plugins/clangcodemodel/clangcompletioncontextanalyzer.cpp index 1cb2fcdf482..b0fe3c4fc5d 100644 --- a/src/plugins/clangcodemodel/clangcompletioncontextanalyzer.cpp +++ b/src/plugins/clangcodemodel/clangcompletioncontextanalyzer.cpp @@ -39,6 +39,7 @@ #include #include #include +#include using namespace CPlusPlus; @@ -65,15 +66,6 @@ bool isTokenForPassThrough(unsigned tokenKind) namespace ClangCodeModel { namespace Internal { -ClangCompletionContextAnalyzer::ClangCompletionContextAnalyzer( - const ClangCompletionAssistInterface *assistInterface, - CPlusPlus::LanguageFeatures languageFeatures) - : ClangCompletionContextAnalyzer(assistInterface->textDocument(), assistInterface->position(), - assistInterface->type() == CompletionType::FunctionHint, - languageFeatures) -{ -} - ClangCompletionContextAnalyzer::ClangCompletionContextAnalyzer( QTextDocument *document, int position, bool isFunctionHint, CPlusPlus::LanguageFeatures languageFeatures) diff --git a/src/plugins/clangcodemodel/clangcompletioncontextanalyzer.h b/src/plugins/clangcodemodel/clangcompletioncontextanalyzer.h index 18cebdb36f3..53dbe8093e0 100644 --- a/src/plugins/clangcodemodel/clangcompletioncontextanalyzer.h +++ b/src/plugins/clangcodemodel/clangcompletioncontextanalyzer.h @@ -38,14 +38,9 @@ namespace TextEditor { class AssistInterface; } namespace ClangCodeModel { namespace Internal { -class ClangCompletionAssistInterface; - class ClangCompletionContextAnalyzer { public: - ClangCompletionContextAnalyzer() = delete; - ClangCompletionContextAnalyzer(const ClangCompletionAssistInterface *assistInterface, - CPlusPlus::LanguageFeatures languageFeatures); ClangCompletionContextAnalyzer(QTextDocument *document, int position, bool isFunctionHint, CPlusPlus::LanguageFeatures languageFeatures); void analyze(); diff --git a/src/plugins/clangcodemodel/clangdclient.cpp b/src/plugins/clangcodemodel/clangdclient.cpp index b683f4b6be2..c4090cd6490 100644 --- a/src/plugins/clangcodemodel/clangdclient.cpp +++ b/src/plugins/clangcodemodel/clangdclient.cpp @@ -25,7 +25,6 @@ #include "clangdclient.h" -#include "clangcompletionassistprocessor.h" #include "clangcompletioncontextanalyzer.h" #include "clangconstants.h" #include "clangdqpropertyhighlighter.h" @@ -903,8 +902,7 @@ private: = projectPartForFile(interface->filePath().toString()); if (projectPart) headerPaths = projectPart->headerPaths; - completions = ClangCompletionAssistProcessor::completeInclude( - m_endPos, m_completionOperator, interface, headerPaths); + completions = completeInclude(m_endPos, m_completionOperator, interface, headerPaths); break; } } @@ -927,6 +925,107 @@ private: return item; } + /** + * @brief Creates completion proposals for #include and given cursor + * @param position - cursor placed after opening bracked or quote + * @param completionOperator - the type of token + * @param interface - relevant document data + * @param headerPaths - the include paths + * @return the list of completion items + */ + static QList completeInclude( + int position, unsigned completionOperator, const TextEditor::AssistInterface *interface, + const ProjectExplorer::HeaderPaths &headerPaths) + { + QTextCursor cursor(interface->textDocument()); + cursor.setPosition(position); + QString directoryPrefix; + if (completionOperator == T_SLASH) { + QTextCursor c = cursor; + c.movePosition(QTextCursor::StartOfLine, QTextCursor::KeepAnchor); + QString sel = c.selectedText(); + int startCharPos = sel.indexOf(QLatin1Char('"')); + if (startCharPos == -1) { + startCharPos = sel.indexOf(QLatin1Char('<')); + completionOperator = T_ANGLE_STRING_LITERAL; + } else { + completionOperator = T_STRING_LITERAL; + } + if (startCharPos != -1) + directoryPrefix = sel.mid(startCharPos + 1, sel.length() - 1); + } + + // Make completion for all relevant includes + ProjectExplorer::HeaderPaths allHeaderPaths = headerPaths; + const auto currentFilePath = ProjectExplorer::HeaderPath::makeUser( + interface->filePath().toFileInfo().path()); + if (!allHeaderPaths.contains(currentFilePath)) + allHeaderPaths.append(currentFilePath); + + const ::Utils::MimeType mimeType = ::Utils::mimeTypeForName("text/x-c++hdr"); + const QStringList suffixes = mimeType.suffixes(); + + QList completions; + foreach (const ProjectExplorer::HeaderPath &headerPath, allHeaderPaths) { + QString realPath = headerPath.path; + if (!directoryPrefix.isEmpty()) { + realPath += QLatin1Char('/'); + realPath += directoryPrefix; + if (headerPath.type == ProjectExplorer::HeaderPathType::Framework) + realPath += QLatin1String(".framework/Headers"); + } + completions << completeIncludePath(realPath, suffixes, completionOperator); + } + + QList> completionsForSorting; + for (AssistProposalItemInterface * const item : qAsConst(completions)) { + QString s = item->text(); + s.replace('/', QChar(0)); // The dir separator should compare less than anything else. + completionsForSorting << qMakePair(item, s); + } + Utils::sort(completionsForSorting, [](const auto &left, const auto &right) { + return left.second < right.second; + }); + for (int i = 0; i < completionsForSorting.count(); ++i) + completions[i] = completionsForSorting[i].first; + + return completions; + } + + /** + * @brief Finds #include completion proposals using given include path + * @param realPath - one of directories where compiler searches includes + * @param suffixes - file suffixes for C/C++ header files + * @return a list of matching completion items + */ + static QList completeIncludePath( + const QString &realPath, const QStringList &suffixes, unsigned completionOperator) + { + QList completions; + QDirIterator i(realPath, QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot); + //: Parent folder for proposed #include completion + const QString hint = ClangdClient::tr("Location: %1") + .arg(QDir::toNativeSeparators(QDir::cleanPath(realPath))); + while (i.hasNext()) { + const QString fileName = i.next(); + const QFileInfo fileInfo = i.fileInfo(); + const QString suffix = fileInfo.suffix(); + if (suffix.isEmpty() || suffixes.contains(suffix)) { + QString text = fileName.mid(realPath.length() + 1); + if (fileInfo.isDir()) + text += QLatin1Char('/'); + + auto *item = new ClangPreprocessorAssistProposalItem; + item->setText(text); + item->setDetail(hint); + item->setIcon(CPlusPlus::Icons::keywordIcon()); + item->setCompletionOperator(completionOperator); + completions.append(item); + } + } + return completions; + } + ClangdClient * const m_client; const int m_position; const int m_endPos; diff --git a/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp b/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp index a1635b885a5..8849aa9dc42 100644 --- a/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp +++ b/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp @@ -153,7 +153,7 @@ CppEditor::SemanticInfo ClangEditorDocumentProcessor::recalculateSemanticInfo() CppEditor::BaseEditorDocumentParser::Ptr ClangEditorDocumentProcessor::parser() { - return m_parser; + return m_builtinProcessor.parser(); } CPlusPlus::Snapshot ClangEditorDocumentProcessor::snapshot() diff --git a/src/plugins/clangcodemodel/clangfunctionhintmodel.cpp b/src/plugins/clangcodemodel/clangfunctionhintmodel.cpp deleted file mode 100644 index 6e33c649d3f..00000000000 --- a/src/plugins/clangcodemodel/clangfunctionhintmodel.cpp +++ /dev/null @@ -1,125 +0,0 @@ -/**************************************************************************** -** -** 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 "clangfunctionhintmodel.h" - -#include "clangcompletionchunkstotextconverter.h" - -#include - -namespace ClangCodeModel { -namespace Internal { - -using namespace CPlusPlus; - -ClangFunctionHintModel::ClangFunctionHintModel(const ClangBackEnd::CodeCompletions &functionSymbols) - : m_functionSymbols(functionSymbols) - , m_currentArgument(-1) -{ -} - -void ClangFunctionHintModel::reset() -{ -} - -int ClangFunctionHintModel::size() const -{ - return m_functionSymbols.size(); -} - -QString ClangFunctionHintModel::text(int index) const -{ - const ClangBackEnd::CodeCompletionChunks &chunks = m_functionSymbols.at(index).chunks; - const QString signatureWithEmphasizedCurrentParameter - = CompletionChunksToTextConverter::convertToFunctionSignatureWithHtml( - chunks, - m_functionSymbols.at(index).completionKind, - m_currentArgument + 1); - - return signatureWithEmphasizedCurrentParameter; -} - -QString ClangFunctionHintModel::id(int index) const -{ - QString chunks; - for (const ClangBackEnd::CodeCompletionChunk &chunk : m_functionSymbols.at(index).chunks) - chunks += chunk.text; - - return chunks; -} - -int ClangFunctionHintModel::activeArgument(const QString &prefix) const -{ - int activeArgumentNumber = 0; - - int unbalancedParens = 0; // expressions - int unbalancedBraces = 0; // initializer lists - int unbalancedBrackets = 0; // lambda-capture - int unbalancedLessGreater = 0; // template arguments - - SimpleLexer tokenize; - const Tokens tokens = tokenize(prefix); - for (const Token &token : tokens) { - if (token.is(T_LPAREN)) { - ++unbalancedParens; - } else if (token.is(T_RPAREN)) { - --unbalancedParens; - } else if (token.is(T_LBRACE)) { - ++unbalancedBraces; - } else if (token.is(T_RBRACE)) { - --unbalancedBraces; - } else if (token.is(T_LBRACKET)) { - ++unbalancedBrackets; - } else if (token.is(T_RBRACKET)) { - --unbalancedBrackets; - } else if (token.is(T_LESS)) { - ++unbalancedLessGreater; - } else if (token.is(T_GREATER)) { - --unbalancedLessGreater; - } else if (!unbalancedParens - && !unbalancedBraces - && !unbalancedBrackets - && !unbalancedLessGreater - && token.is(T_COMMA)) { - ++activeArgumentNumber; - } - } - - if (unbalancedParens < 0 - || unbalancedBraces < 0 - || unbalancedBrackets < 0 - || unbalancedLessGreater < 0) { - return -1; - } - - if (activeArgumentNumber != m_currentArgument) - m_currentArgument = activeArgumentNumber; - - return activeArgumentNumber; -} - -} // namespace Internal -} // namespace ClangCodeModel - diff --git a/src/plugins/clangcodemodel/clangfunctionhintmodel.h b/src/plugins/clangcodemodel/clangfunctionhintmodel.h deleted file mode 100644 index 9a848025a4d..00000000000 --- a/src/plugins/clangcodemodel/clangfunctionhintmodel.h +++ /dev/null @@ -1,52 +0,0 @@ -/**************************************************************************** -** -** 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. -** -****************************************************************************/ - -#pragma once - -#include - -#include - -namespace ClangCodeModel { -namespace Internal { - -class ClangFunctionHintModel : public TextEditor::IFunctionHintProposalModel -{ -public: - ClangFunctionHintModel(const ClangBackEnd::CodeCompletions &functionSymbols); - - void reset() override; - int size() const override; - QString text(int index) const override; - QString id(int index) const override; - int activeArgument(const QString &prefix) const override; - -private: - ClangBackEnd::CodeCompletions m_functionSymbols; - mutable int m_currentArgument; -}; - -} // namespace Internal -} // namespace ClangCodeModel diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp index d56d3da5f90..53f2e68d5eb 100644 --- a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp +++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp @@ -104,10 +104,7 @@ static const QList allCppDocuments() return Utils::qobject_container_cast(documents); } -ClangModelManagerSupport::ClangModelManagerSupport() - : m_completionAssistProvider(m_communicator, CompletionType::Other) - , m_functionHintAssistProvider(m_communicator, CompletionType::FunctionHint) - , m_refactoringEngine(new RefactoringEngine) +ClangModelManagerSupport::ClangModelManagerSupport() : m_refactoringEngine(new RefactoringEngine) { QTC_CHECK(!m_instance); m_instance = this; @@ -175,12 +172,12 @@ ClangModelManagerSupport::~ClangModelManagerSupport() CppEditor::CppCompletionAssistProvider *ClangModelManagerSupport::completionAssistProvider() { - return &m_completionAssistProvider; + return nullptr; } CppEditor::CppCompletionAssistProvider *ClangModelManagerSupport::functionHintAssistProvider() { - return &m_functionHintAssistProvider; + return nullptr; } void ClangModelManagerSupport::followSymbol(const CppEditor::CursorInEditor &data, diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.h b/src/plugins/clangcodemodel/clangmodelmanagersupport.h index 99d21b9bc94..af4bb185f62 100644 --- a/src/plugins/clangcodemodel/clangmodelmanagersupport.h +++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.h @@ -25,7 +25,7 @@ #pragma once -#include "clangcompletionassistprovider.h" +#include "clangbackendcommunicator.h" #include "clanguiheaderondiskmanager.h" #include @@ -143,8 +143,6 @@ private: UiHeaderOnDiskManager m_uiHeaderOnDiskManager; BackendCommunicator m_communicator; - ClangCompletionAssistProvider m_completionAssistProvider; - ClangCompletionAssistProvider m_functionHintAssistProvider; std::unique_ptr m_refactoringEngine; QHash m_projectSettings; diff --git a/src/plugins/clangcodemodel/test/clangautomationutils.cpp b/src/plugins/clangcodemodel/test/clangautomationutils.cpp deleted file mode 100644 index ec2b6e9207c..00000000000 --- a/src/plugins/clangcodemodel/test/clangautomationutils.cpp +++ /dev/null @@ -1,140 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 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 "clangautomationutils.h" - -#include "../clangcompletionassistinterface.h" -#include "../clangcompletionassistprovider.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -namespace ClangCodeModel { -namespace Internal { - -class WaitForAsyncCompletions -{ -public: - enum WaitResult { GotResults, GotInvalidResults, Timeout }; - - WaitResult wait(TextEditor::IAssistProcessor *processor, - TextEditor::AssistInterface *assistInterface, - int timeoutInMs) - { - QTC_ASSERT(processor, return Timeout); - QTC_ASSERT(assistInterface, return Timeout); - - bool gotResults = false; - - processor->setAsyncCompletionAvailableHandler( - [this, processor, &gotResults] (TextEditor::IAssistProposal *proposal) { - QTC_ASSERT(proposal, return); - QTC_CHECK(!processor->running()); - proposalModel = proposal->model(); - delete proposal; - gotResults = true; - }); - - // Are there any immediate results? - if (TextEditor::IAssistProposal *proposal = processor->perform(assistInterface)) { - proposalModel = proposal->model(); - delete proposal; - QTC_ASSERT(proposalModel, return GotInvalidResults); - return GotResults; - } - - // There are not any, so wait for async results. - QElapsedTimer timer; - timer.start(); - while (!gotResults) { - if (timer.elapsed() >= timeoutInMs) { - processor->cancel(); - return Timeout; - } - QCoreApplication::processEvents(); - } - - return proposalModel ? GotResults : GotInvalidResults; - } - -public: - TextEditor::ProposalModelPtr proposalModel; -}; - -TextEditor::ProposalModelPtr completionResults(TextEditor::BaseTextEditor *textEditor, - const QStringList &includePaths, - int timeOutInMs) -{ - using namespace TextEditor; - - auto textEditorWidget = TextEditorWidget::fromEditor(textEditor); - QTC_ASSERT(textEditorWidget, return TextEditor::ProposalModelPtr()); - AssistInterface *assistInterface = textEditorWidget->createAssistInterface( - TextEditor::Completion, TextEditor::ExplicitlyInvoked); - QTC_ASSERT(assistInterface, return TextEditor::ProposalModelPtr()); - if (!includePaths.isEmpty()) { - auto clangAssistInterface = static_cast(assistInterface); - clangAssistInterface->setHeaderPaths(ProjectExplorer::toUserHeaderPaths(includePaths)); - } - - CompletionAssistProvider *assistProvider - = textEditor->textDocument()->completionAssistProvider(); - QTC_ASSERT(qobject_cast(assistProvider), - return TextEditor::ProposalModelPtr()); - QTC_ASSERT(assistProvider, return TextEditor::ProposalModelPtr()); - QTC_ASSERT(assistProvider->runType() == IAssistProvider::Asynchronous, - return TextEditor::ProposalModelPtr()); - - QScopedPointer processor(assistProvider->createProcessor(assistInterface)); - QTC_ASSERT(processor, return TextEditor::ProposalModelPtr()); - - WaitForAsyncCompletions waitForCompletions; - const WaitForAsyncCompletions::WaitResult result = waitForCompletions.wait(processor.data(), - assistInterface, - timeOutInMs); - QTC_ASSERT(result == WaitForAsyncCompletions::GotResults, - return TextEditor::ProposalModelPtr()); - return waitForCompletions.proposalModel; -} - -QString qrcPath(const QByteArray &relativeFilePath) -{ - return QLatin1String(":/unittests/ClangCodeModel/") + QString::fromUtf8(relativeFilePath); -} - -} // namespace Internal -} // namespace ClangCodeModel diff --git a/src/plugins/clangcodemodel/test/clangautomationutils.h b/src/plugins/clangcodemodel/test/clangautomationutils.h deleted file mode 100644 index 7b9a5bb262e..00000000000 --- a/src/plugins/clangcodemodel/test/clangautomationutils.h +++ /dev/null @@ -1,46 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 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. -** -****************************************************************************/ - -#pragma once - -#include - -#include -#include -#include - -namespace TextEditor { class BaseTextEditor; } - -namespace ClangCodeModel { -namespace Internal { - -TextEditor::ProposalModelPtr completionResults(TextEditor::BaseTextEditor *textEditor, - const QStringList &includePaths = QStringList(), - int timeOutInMs = 10000); - -QString qrcPath(const QByteArray &relativeFilePath); - -} // namespace Internal -} // namespace ClangCodeModel diff --git a/src/plugins/clangcodemodel/test/clangbatchfileprocessor.cpp b/src/plugins/clangcodemodel/test/clangbatchfileprocessor.cpp index a5041ea1c98..ce17550ea30 100644 --- a/src/plugins/clangcodemodel/test/clangbatchfileprocessor.cpp +++ b/src/plugins/clangcodemodel/test/clangbatchfileprocessor.cpp @@ -25,8 +25,6 @@ #include "clangbatchfileprocessor.h" -#include "clangautomationutils.h" - #include #include @@ -442,45 +440,6 @@ Command::Ptr InsertTextCommand::parse(BatchFileLineTokenizer &arguments, return Command::Ptr(new InsertTextCommand(context, textToInsert)); } -class CompleteCommand : public Command -{ -public: - CompleteCommand(const CommandContext &context); - - bool run() override; - - static Command::Ptr parse(BatchFileLineTokenizer &arguments, - const CommandContext &context); -}; - -CompleteCommand::CompleteCommand(const CommandContext &context) - : Command(context) -{ -} - -bool CompleteCommand::run() -{ - qCDebug(debug) << "line" << context().lineNumber << "CompleteCommand"; - - TextEditor::BaseTextEditor *editor = currentTextEditor(); - QTC_ASSERT(editor, return false); - - const QString documentFilePath = editor->document()->filePath().toString(); - auto *processor = ClangEditorDocumentProcessor::get(documentFilePath); - QTC_ASSERT(processor, return false); - - return !completionResults(editor, QStringList(), timeOutInMs()).isNull(); -} - -Command::Ptr CompleteCommand::parse(BatchFileLineTokenizer &arguments, - const CommandContext &context) -{ - Q_UNUSED(arguments) - Q_UNUSED(context) - - return Command::Ptr(new CompleteCommand(context)); -} - class SetCursorCommand : public Command { public: @@ -687,7 +646,6 @@ BatchFileParser::BatchFileParser(const QString &filePath, m_commandParsers.insert("closeAllDocuments", &CloseAllDocuments::parse); m_commandParsers.insert("setCursor", &SetCursorCommand::parse); m_commandParsers.insert("insertText", &InsertTextCommand::parse); - m_commandParsers.insert("complete", &CompleteCommand::parse); m_commandParsers.insert("processEvents", &ProcessEventsCommand::parse); } diff --git a/src/plugins/clangcodemodel/test/clangcodecompletion_test.cpp b/src/plugins/clangcodemodel/test/clangcodecompletion_test.cpp deleted file mode 100644 index 4fa51c94b7c..00000000000 --- a/src/plugins/clangcodemodel/test/clangcodecompletion_test.cpp +++ /dev/null @@ -1,846 +0,0 @@ -/**************************************************************************** -** -** 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 "clangcodecompletion_test.h" - -#include "clangautomationutils.h" -#include "clangbatchfileprocessor.h" -#include "../clangcompletionassistinterface.h" -#include "../clangmodelmanagersupport.h" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include - -#include -#include - -using namespace ClangCodeModel; -using namespace ClangCodeModel::Internal; - -namespace { - -CppEditor::Tests::TemporaryDir *globalTemporaryDir() -{ - static CppEditor::Tests::TemporaryDir dir; - QTC_CHECK(dir.isValid()); - return &dir; -} - -QByteArray readFile(const QString &filePath) -{ - QFile file(filePath); - QTC_ASSERT(file.open(QFile::ReadOnly | QFile::Text), return QByteArray()); - return file.readAll(); -} - -bool writeFile(const QString &filePath, const QByteArray &contents) -{ - QFile file(filePath); - if (!file.open(QFile::WriteOnly | QFile::Text)) - return false; - if (file.write(contents) != contents.size()) - return false; - return true; -} - -class ChangeDocumentReloadSetting -{ -public: - ChangeDocumentReloadSetting(Core::IDocument::ReloadSetting reloadSetting) - : m_previousValue(Core::EditorManager::reloadSetting()) - { - Core::EditorManager::setReloadSetting(reloadSetting); - } - - ~ChangeDocumentReloadSetting() - { - Core::EditorManager::setReloadSetting(m_previousValue); - } - -private: - Core::IDocument::ReloadSetting m_previousValue; -}; - -class TestDocument -{ -public: - TestDocument(const QByteArray &fileName, CppEditor::Tests::TemporaryDir *temporaryDir = nullptr) - { - QTC_ASSERT(!fileName.isEmpty(), return); - const QResource resource(qrcPath("completion/" + fileName)); - QTC_ASSERT(resource.isValid(), return); - const QByteArray contents = QByteArray(reinterpret_cast(resource.data()), - resource.size()); - finish(fileName, contents, temporaryDir); - } - - static TestDocument fromExistingFile(const QString &filePath) - { - TestDocument testDocument; - QTC_ASSERT(!filePath.isEmpty(), return testDocument); - testDocument.filePath = filePath; - testDocument.cursorPosition = findCursorMarkerPosition(readFile(filePath)); - return testDocument; - } - - static TestDocument fromString(const QByteArray &fileName, const QByteArray &contents, - CppEditor::Tests::TemporaryDir *tempDir = nullptr) - { - TestDocument testDocument; - testDocument.finish(fileName, contents, tempDir); - return testDocument; - } - - static int findCursorMarkerPosition(const QByteArray &contents) - { - return contents.indexOf(" /* COMPLETE HERE */"); - } - - bool isCreated() const { return !filePath.isEmpty(); } - bool hasValidCursorPosition() const { return cursorPosition >= 0; } - bool isCreatedAndHasValidCursorPosition() const - { return isCreated() && hasValidCursorPosition(); } - - QString filePath; - int cursorPosition = -1; - -private: - TestDocument() = default; - - void finish(const QByteArray &fileName, const QByteArray &contents, - CppEditor::Tests::TemporaryDir *temporaryDir = nullptr) - { - cursorPosition = findCursorMarkerPosition(contents); - if (!contents.isEmpty()) { - if (!temporaryDir) { - m_temporaryDir.reset(new CppEditor::Tests::TemporaryDir); - temporaryDir = m_temporaryDir.data(); - } - - filePath = temporaryDir->createFile(fileName, contents); - } - } - - QSharedPointer m_temporaryDir; -}; - -class OpenEditorAtCursorPosition -{ -public: - OpenEditorAtCursorPosition(const TestDocument &testDocument); - ~OpenEditorAtCursorPosition(); // Close editor - - bool succeeded() const { return m_editor && m_backendIsNotified; } - bool waitUntilBackendIsNotified(int timeout = 10000); - bool waitUntilProjectPartChanged(const QString &newProjectPartId, int timeout = 10000); - bool waitUntil(const std::function &condition, int timeout); - TextEditor::BaseTextEditor *editor() const { return m_editor; } - -private: - TextEditor::BaseTextEditor *m_editor; - bool m_backendIsNotified = false; -}; - -OpenEditorAtCursorPosition::OpenEditorAtCursorPosition(const TestDocument &testDocument) -{ - Core::IEditor *coreEditor = Core::EditorManager::openEditor( - Utils::FilePath::fromString(testDocument.filePath)); - m_editor = qobject_cast(coreEditor); - QTC_CHECK(m_editor); - if (m_editor) { - if (testDocument.hasValidCursorPosition()) - m_editor->setCursorPosition(testDocument.cursorPosition); - m_backendIsNotified = waitUntilBackendIsNotified(); - } - QTC_CHECK(m_backendIsNotified); -} - -OpenEditorAtCursorPosition::~OpenEditorAtCursorPosition() -{ - if (m_editor) - Core::EditorManager::closeEditors({m_editor}, /* askAboutModifiedEditors= */ false); -} - - - -bool OpenEditorAtCursorPosition::waitUntilBackendIsNotified(int timeout) -{ - const QString filePath = m_editor->document()->filePath().toString(); - - auto condition = [filePath] () { - const auto *processor = ClangEditorDocumentProcessor::get(filePath); - return processor && processor->projectPart(); - }; - - return waitUntil(condition, timeout); -} - -bool OpenEditorAtCursorPosition::waitUntilProjectPartChanged(const QString &newProjectPartId, - int timeout) -{ - const QString filePath = m_editor->document()->filePath().toString(); - - auto condition = [newProjectPartId, filePath] () { - const auto *processor = ClangEditorDocumentProcessor::get(filePath); - return processor - && processor->projectPart() - && processor->projectPart()->id() == newProjectPartId; - }; - - return waitUntil(condition, timeout); -} - -bool OpenEditorAtCursorPosition::waitUntil(const std::function &condition, int timeout) -{ - QElapsedTimer time; - time.start(); - - forever { - if (time.elapsed() > timeout) - return false; - - if (condition()) - return true; - - QCoreApplication::processEvents(); - QThread::msleep(20); - } - - return false; -} - -CppEditor::ProjectPart::ConstPtr createProjectPart(const Utils::FilePath &projectFilePath, - const QStringList &files, - const ProjectExplorer::Macros ¯os) -{ - using namespace CppEditor; - - ProjectExplorer::RawProjectPart rpp; - rpp.setProjectFileLocation("myproject.project"); - rpp.setQtVersion(Utils::QtMajorVersion::None); - rpp.setMacros(macros); - const auto projectFiles = Utils::transform(files, [](const QString &f) { - return ProjectFile(f, ProjectFile::classify(f)); - }); - return ProjectPart::create(projectFilePath, rpp, {}, projectFiles); -} - -CppEditor::ProjectInfo::ConstPtr createProjectInfo(ProjectExplorer::Project *project, - const QStringList &files, - const ProjectExplorer::Macros ¯os) -{ - using namespace CppEditor; - QTC_ASSERT(project, return {}); - - const CppEditor::ProjectPart::ConstPtr projectPart - = createProjectPart(project->projectFilePath(), files, macros); - const auto projectInfo = ProjectInfo::create( - {project, ProjectExplorer::KitInfo(nullptr), {}, {}}, {projectPart}); - return projectInfo; -} - -class ProjectLoader -{ -public: - ProjectLoader(const QStringList &projectFiles, - const ProjectExplorer::Macros &projectMacros, - bool testOnlyForCleanedProjects = false) - : m_project(nullptr) - , m_projectFiles(projectFiles) - , m_projectMacros(projectMacros) - , m_helper(nullptr, testOnlyForCleanedProjects) - { - } - - bool load() - { - m_project = m_helper.createProject(QLatin1String("testProject")); - const CppEditor::ProjectInfo::ConstPtr projectInfo = createProjectInfo(m_project, - m_projectFiles, - m_projectMacros); - const QSet filesIndexedAfterLoading = m_helper.updateProjectInfo(projectInfo); - return m_projectFiles.size() == filesIndexedAfterLoading.size(); - } - - bool updateProject(const ProjectExplorer::Macros &updatedProjectMacros) - { - QTC_ASSERT(m_project, return false); - const CppEditor::ProjectInfo::ConstPtr updatedProjectInfo - = createProjectInfo(m_project, m_projectFiles, updatedProjectMacros); - return updateProjectInfo(updatedProjectInfo); - - } - -private: - bool updateProjectInfo(const CppEditor::ProjectInfo::ConstPtr &projectInfo) - { - const QSet filesIndexedAfterLoading = m_helper.updateProjectInfo(projectInfo); - return m_projectFiles.size() == filesIndexedAfterLoading.size(); - } - - ProjectExplorer::Project *m_project; - QStringList m_projectFiles; - ProjectExplorer::Macros m_projectMacros; - CppEditor::Tests::ModelManagerTestHelper m_helper; -}; - -class ProjectLessCompletionTest -{ -public: - ProjectLessCompletionTest(const QByteArray &testFileName, - const QString &textToInsert = QString(), - const QStringList &includePaths = QStringList(), - const QByteArray &contents = {}) - { - CppEditor::Tests::TestCase garbageCollectionGlobalSnapshot; - QVERIFY(garbageCollectionGlobalSnapshot.succeededSoFar()); - - const auto testDocument = contents.isEmpty() - ? TestDocument(testFileName, globalTemporaryDir()) - : TestDocument::fromString(testFileName, contents, globalTemporaryDir()); - QVERIFY(testDocument.isCreatedAndHasValidCursorPosition()); - OpenEditorAtCursorPosition openEditor(testDocument); - QVERIFY(openEditor.succeeded()); - - if (!textToInsert.isEmpty()) - openEditor.editor()->insert(textToInsert); - - proposal = completionResults(openEditor.editor(), includePaths, timeOutInMs()); - } - - TextEditor::ProposalModelPtr proposal; -}; - -int indexOfItemWithText(TextEditor::ProposalModelPtr model, const QByteArray &text) -{ - if (!model) - return -1; - - for (int i = 0, size = model->size(); i < size; ++i) { - const QString itemText = model->text(i); - if (itemText == QString::fromUtf8(text)) - return i; - } - - return -1; -} - -bool hasItem(TextEditor::ProposalModelPtr model, const QByteArray &text) -{ - return indexOfItemWithText(model, text) != -1; -} - -int itemsWithText(TextEditor::ProposalModelPtr model, const QByteArray &text) -{ - if (!model) - return 0; - - int amount = 0; - for (int i = 0, size = model->size(); i < size; ++i) { - if (model->text(i) == QString::fromUtf8(text)) - ++amount; - } - - return amount; -} - -bool hasItem(TextEditor::ProposalModelPtr model, const QByteArray &text, const QByteArray &detail) -{ - const int index = indexOfItemWithText(model, text); - if (index != -1 && index < model->size()) { - TextEditor::IAssistProposalModel *imodel = model.data(); - const auto genericModel = static_cast(imodel); - const auto itemDetail = genericModel->detail(index); - return itemDetail == QString::fromUtf8(detail); - } - - return false; -} - -bool hasSnippet(TextEditor::ProposalModelPtr model, const QByteArray &text) -{ - if (!model) - return false; - - // Snippets seem to end with a whitespace - const QString snippetText = QString::fromUtf8(text) + QLatin1Char(' '); - - auto *genericModel = static_cast(model.data()); - for (int i = 0, size = genericModel->size(); i < size; ++i) { - TextEditor::AssistProposalItemInterface *item = genericModel->proposalItem(i); - QTC_ASSERT(item, continue); - if (item->text() == snippetText) - return item->isSnippet(); - } - - return false; -} - -class MonitorGeneratedUiFile : public QObject -{ -public: - MonitorGeneratedUiFile(); - bool waitUntilGenerated(int timeout = 10000) const; - -private: - void onUiFileGenerated() { m_isGenerated = true; } - - bool m_isGenerated = false; -}; - -MonitorGeneratedUiFile::MonitorGeneratedUiFile() -{ - connect(CppEditor::CppModelManager::instance(), - &CppEditor::CppModelManager::abstractEditorSupportContentsUpdated, - this, &MonitorGeneratedUiFile::onUiFileGenerated); -} - -bool MonitorGeneratedUiFile::waitUntilGenerated(int timeout) const -{ - if (m_isGenerated) - return true; - - QElapsedTimer time; - time.start(); - - forever { - if (m_isGenerated) - return true; - - if (time.elapsed() > timeout) - return false; - - QCoreApplication::processEvents(); - QThread::msleep(20); - } - - return false; -} - -class WriteFileAndWaitForReloadedDocument : public QObject -{ -public: - WriteFileAndWaitForReloadedDocument(const QString &filePath, - const QByteArray &fileContents, - Core::IDocument *document) - : m_filePath(filePath) - , m_fileContents(fileContents) - { - QTC_CHECK(document); - connect(document, &Core::IDocument::reloadFinished, - this, &WriteFileAndWaitForReloadedDocument::onReloadFinished); - } - - void onReloadFinished() - { - m_onReloadFinished = true; - } - - bool wait() const - { - QTC_ASSERT(writeFile(m_filePath, m_fileContents), return false); - - QElapsedTimer totalTime; - totalTime.start(); - - QElapsedTimer writeFileAgainTime; - writeFileAgainTime.start(); - - forever { - if (m_onReloadFinished) - return true; - - if (totalTime.elapsed() > 10000) - return false; - - if (writeFileAgainTime.elapsed() > 3000) { - // The timestamp did not change, try again now. - QTC_ASSERT(writeFile(m_filePath, m_fileContents), return false); - writeFileAgainTime.restart(); - } - - QCoreApplication::processEvents(); - QThread::msleep(20); - } - } - -private: - bool m_onReloadFinished = false; - QString m_filePath; - QByteArray m_fileContents; -}; - -} // anonymous namespace - -namespace ClangCodeModel { -namespace Internal { -namespace Tests { - -void ClangCodeCompletionTest::initTestCase() -{ - CppEditor::ClangdSettings::setUseClangd(false); - for (LanguageClient::Client * const c : LanguageClient::LanguageClientManager::clients()) - LanguageClient::LanguageClientManager::shutdownClient(c); -} - -void ClangCodeCompletionTest::testCompleteDoxygenKeywords() -{ - ProjectLessCompletionTest t("doxygenKeywordsCompletion.cpp"); - - QVERIFY(hasItem(t.proposal, "brief")); - QVERIFY(hasItem(t.proposal, "param")); - QVERIFY(hasItem(t.proposal, "return")); - QVERIFY(!hasSnippet(t.proposal, "class")); -} - -void ClangCodeCompletionTest::testCompletePreprocessorKeywords() -{ - ProjectLessCompletionTest t("preprocessorKeywordsCompletion.cpp"); - - QVERIFY(hasItem(t.proposal, "ifdef")); - QVERIFY(hasItem(t.proposal, "endif")); - QVERIFY(!hasSnippet(t.proposal, "class")); -} - -void ClangCodeCompletionTest::testCompleteIncludeDirective() -{ - CppEditor::Tests::TemporaryCopiedDir testDir(qrcPath("completion/exampleIncludeDir")); - ProjectLessCompletionTest t("includeDirectiveCompletion.cpp", - QString(), - QStringList(testDir.path())); - - QVERIFY(hasItem(t.proposal, "file.h")); - QVERIFY(hasItem(t.proposal, "otherFile.h")); - QVERIFY(hasItem(t.proposal, "mylib/")); - QVERIFY(!hasSnippet(t.proposal, "class")); -} - -void ClangCodeCompletionTest::testCompleteGlobals() -{ - ProjectLessCompletionTest t("globalCompletion.cpp"); - - QVERIFY(hasItem(t.proposal, "globalVariable", "int globalVariable")); - QVERIFY(hasItem(t.proposal, "globalFunction", "void globalFunction()")); - QVERIFY(hasItem(t.proposal, "GlobalClass", "GlobalClass")); - QVERIFY(hasItem(t.proposal, "class", "class")); // Keyword - QVERIFY(hasSnippet(t.proposal, "class")); // Snippet -} - -void ClangCodeCompletionTest::testCompleteMembers() -{ - ProjectLessCompletionTest t("memberCompletion.cpp"); - - QVERIFY(hasItem(t.proposal, "member")); - QVERIFY(!hasItem(t.proposal, "globalVariable")); - QVERIFY(!hasItem(t.proposal, "class")); // Keyword - QVERIFY(!hasSnippet(t.proposal, "class")); // Snippet -} - -void ClangCodeCompletionTest::testCompleteMembersFromInside() -{ - ProjectLessCompletionTest t("membercompletion-inside.cpp"); - - QVERIFY(hasItem(t.proposal, "publicFunc")); - QVERIFY(hasItem(t.proposal, "privateFunc")); -} - -void ClangCodeCompletionTest::testCompleteMembersFromOutside() -{ - ProjectLessCompletionTest t("membercompletion-outside.cpp"); - - QVERIFY(hasItem(t.proposal, "publicFunc")); - QVERIFY(!hasItem(t.proposal, "privateFunc")); -} - -void ClangCodeCompletionTest::testCompleteMembersFromFriend() -{ - ProjectLessCompletionTest t("membercompletion-friend.cpp"); - - QVERIFY(hasItem(t.proposal, "publicFunc")); - QVERIFY(hasItem(t.proposal, "privateFunc")); -} - -void ClangCodeCompletionTest::testCompleteFunctions() -{ - ProjectLessCompletionTest t("functionCompletion.cpp"); - - QVERIFY(hasItem(t.proposal, "void f()")); - QVERIFY(hasItem(t.proposal, "void f(int a)")); - QVERIFY(hasItem(t.proposal, "void f(const QString &s)")); - QVERIFY(hasItem(t.proposal, "void f(char c, int optional = 3)")); - QVERIFY(hasItem(t.proposal, "void f(char c, int optional1 = 3, int optional2 = 3)")); - QVERIFY(hasItem(t.proposal, "void f(const TType<QString> *t)")); - QVERIFY(hasItem(t.proposal, "TType<QString> f(bool)")); -} - -void ClangCodeCompletionTest::testCompleteOverloads() -{ - ProjectLessCompletionTest t("functionCompletionFiltered.cpp"); - QCOMPARE(t.proposal->size(), 1); - QVERIFY(hasItem(t.proposal, "void func(int i, int j)")); - - ProjectLessCompletionTest t2("functionCompletionFiltered2.cpp"); - QCOMPARE(t2.proposal->size(), 2); - QVERIFY(hasItem(t2.proposal, "void func(const S &s, int j)")); - QVERIFY(hasItem(t2.proposal, "void func(const S &s, int j, int k)")); -} - -void ClangCodeCompletionTest::testCompleteConstructor() -{ - ProjectLessCompletionTest t("constructorCompletion.cpp"); - - QVERIFY(!hasItem(t.proposal, "globalVariable")); - QVERIFY(!hasItem(t.proposal, "class")); - QVERIFY(hasItem(t.proposal, "Foo(int)")); - QVERIFY(hasItem(t.proposal, "Foo(int, double)")); -} - -void ClangCodeCompletionTest::testCompleteClassAndConstructor() -{ - ProjectLessCompletionTest t("classAndConstructorCompletion.cpp"); - - QCOMPARE(itemsWithText(t.proposal, "Foo"), 2); -} - -// Explicitly Inserting The Dot -// ---------------------------- -// Inserting the dot for is important since it will send the editor -// content to the backend and thus generate an unsaved file on the backend -// side. The unsaved file enables us to do the dot to arrow correction. - -void ClangCodeCompletionTest::testCompleteWithDotToArrowCorrection() -{ - ProjectLessCompletionTest t("dotToArrowCorrection.cpp", - QStringLiteral(".")); // See above "Explicitly Inserting The Dot" - - QVERIFY(hasItem(t.proposal, "member")); -} - -void ClangCodeCompletionTest::testDontCompleteWithDotToArrowCorrectionForFloats() -{ - ProjectLessCompletionTest t("noDotToArrowCorrectionForFloats.cpp", - QStringLiteral(".")); // See above "Explicitly Inserting The Dot" - - QCOMPARE(t.proposal->size(), 0); -} - -void ClangCodeCompletionTest::testCompleteProjectDependingCode() -{ - const TestDocument testDocument("completionWithProject.cpp"); - QVERIFY(testDocument.isCreatedAndHasValidCursorPosition()); - - ProjectLoader projectLoader(QStringList(testDocument.filePath), {{"PROJECT_CONFIGURATION_1"}}); - QVERIFY(projectLoader.load()); - - OpenEditorAtCursorPosition openEditor(testDocument); - QVERIFY(openEditor.succeeded()); - - TextEditor::ProposalModelPtr proposal = completionResults(openEditor.editor(), {}, - timeOutInMs()); - QVERIFY(hasItem(proposal, "projectConfiguration1")); -} - -void ClangCodeCompletionTest::testCompleteProjectDependingCodeAfterChangingProject() -{ - const TestDocument testDocument("completionWithProject.cpp"); - QVERIFY(testDocument.isCreatedAndHasValidCursorPosition()); - - OpenEditorAtCursorPosition openEditor(testDocument); - QVERIFY(openEditor.succeeded()); - - // Check completion without project - TextEditor::ProposalModelPtr proposal = completionResults(openEditor.editor(), {}, - timeOutInMs()); - QVERIFY(hasItem(proposal, "noProjectConfigurationDetected")); - - { - // Check completion with project configuration 1 - ProjectLoader projectLoader(QStringList(testDocument.filePath), - {{"PROJECT_CONFIGURATION_1"}}, - /* testOnlyForCleanedProjects= */ true); - QVERIFY(projectLoader.load()); - openEditor.waitUntilProjectPartChanged(QLatin1String("myproject.project")); - - proposal = completionResults(openEditor.editor(), {}, timeOutInMs()); - - QVERIFY(hasItem(proposal, "projectConfiguration1")); - QVERIFY(!hasItem(proposal, "projectConfiguration2")); - - // Check completion with project configuration 2 - QVERIFY(projectLoader.updateProject({{"PROJECT_CONFIGURATION_2"}})); - openEditor.waitUntilBackendIsNotified(); - proposal = completionResults(openEditor.editor(), {}, timeOutInMs()); - - QVERIFY(!hasItem(proposal, "projectConfiguration1")); - QVERIFY(hasItem(proposal, "projectConfiguration2")); - } // Project closed - - // Check again completion without project - openEditor.waitUntilProjectPartChanged(QLatin1String("")); - proposal = completionResults(openEditor.editor(), {}, timeOutInMs()); - QVERIFY(hasItem(proposal, "noProjectConfigurationDetected")); -} - -void ClangCodeCompletionTest::testCompleteProjectDependingCodeInGeneratedUiFile() -{ - CppEditor::Tests::TemporaryCopiedDir testDir(qrcPath("qt-widgets-app")); - QVERIFY(testDir.isValid()); - - MonitorGeneratedUiFile monitorGeneratedUiFile; - - // Open project - const QString projectFilePath = testDir.absolutePath("qt-widgets-app.pro"); - CppEditor::Tests::ProjectOpenerAndCloser projectManager; - QVERIFY(projectManager.open(projectFilePath, true)); - QVERIFY(monitorGeneratedUiFile.waitUntilGenerated()); - - // Open file with ui object - const QString completionFile = testDir.absolutePath("mainwindow.cpp"); - const TestDocument testDocument = TestDocument::fromExistingFile(completionFile); - QVERIFY(testDocument.isCreatedAndHasValidCursorPosition()); - OpenEditorAtCursorPosition openSource(testDocument); - QVERIFY(openSource.succeeded()); - - // ...and check comletions - TextEditor::ProposalModelPtr proposal = completionResults(openSource.editor(), {}, - timeOutInMs()); - QVERIFY(hasItem(proposal, "menuBar")); - QVERIFY(hasItem(proposal, "statusBar")); - QVERIFY(hasItem(proposal, "centralWidget")); - QVERIFY(hasItem(proposal, "setupUi")); -} - -static QByteArray makeSignalCompletionContents(const QByteArray &customContents) -{ - static const QByteArray definitions = R"( - class QObject { - public: - void aSignal() __attribute__((annotate("qt_signal"))); - void anotherSignal() __attribute__((annotate("qt_signal"))); - void notASignal(); - static void connect(); - static void disconnect(); - }; - class DerivedFromQObject : public QObject { - public: - void myOwnSignal() __attribute__((annotate("qt_signal"))); - void alsoNotASignal(); - }; - class NotAQObject { - public: - void notASignal(); - void alsoNotASignal(); - static void connect(); - };)"; - - return definitions + customContents + " /* COMPLETE HERE */"; -} - -void ClangCodeCompletionTest::testSignalCompletion_data() -{ - QTest::addColumn("customContents"); - QTest::addColumn("hits"); - - // libclang mis-reports CXCursor_ClassDecl instead of CXCursor_Constructor, so the lists - // below include the class name. - QTest::addRow("positive: connect() on QObject class") - << QByteArray("int main() { QObject::connect(dummy, QObject::") - << QByteArrayList{"aSignal", "anotherSignal", "QObject"}; - QTest::addRow("positive: connect() on QObject object") - << QByteArray("int main() { QObject o; o.connect(dummy, QObject::") - << QByteArrayList{"aSignal", "anotherSignal", "QObject"}; - QTest::addRow("positive: connect() on QObject pointer") - << QByteArray("int main() { QObject *o; o->connect(dummy, QObject::") - << QByteArrayList{"aSignal", "anotherSignal", "QObject"}; - QTest::addRow("positive: connect() on QObject rvalue") - << QByteArray("int main() { QObject().connect(dummy, QObject::") - << QByteArrayList{"aSignal", "anotherSignal", "QObject"}; - QTest::addRow("positive: connect() on QObject pointer rvalue") - << QByteArray("int main() { (new QObject)->connect(dummy, QObject::") - << QByteArrayList{"aSignal", "anotherSignal", "QObject"}; - QTest::addRow("positive: disconnect() on QObject") - << QByteArray("int main() { QObject::disconnect(dummy, QObject::") - << QByteArrayList{"aSignal", "anotherSignal", "QObject"}; - QTest::addRow("positive: connect() in member function of derived class") - << QByteArray("void DerivedFromQObject::alsoNotASignal() { connect(this, DerivedFromQObject::") - << QByteArrayList{"aSignal", "anotherSignal", "myOwnSignal", "QObject", "DerivedFromQObject"}; - - const QByteArrayList allQObjectFunctions{"aSignal", "anotherSignal", "notASignal", "connect", - "disconnect", "QObject", "~QObject", "operator="}; - QTest::addRow("negative: different function name") - << QByteArray("int main() { QObject::notASignal(dummy, QObject::") - << allQObjectFunctions; - QTest::addRow("negative: connect function from other class") - << QByteArray("int main() { NotAQObject::connect(dummy, QObject::") - << allQObjectFunctions; - QTest::addRow("negative: first argument") - << QByteArray("int main() { QObject::connect(QObject::") - << allQObjectFunctions; - QTest::addRow("negative: third argument") - << QByteArray("int main() { QObject::connect(dummy1, dummy2, QObject::") - << allQObjectFunctions; - - QTest::addRow("negative: not a QObject") - << QByteArray("int main() { QObject::connect(dummy, NotAQObject::") - << QByteArrayList{"notASignal", "alsoNotASignal", "connect", "NotAQObject", - "~NotAQObject", "operator="}; -} - - -void ClangCodeCompletionTest::testSignalCompletion() -{ - QFETCH(QByteArray, customContents); - QFETCH(QByteArrayList, hits); - - const QByteArray contents = makeSignalCompletionContents(customContents); - const ProjectLessCompletionTest t("signalcompletion.cpp", {}, {}, contents); - - QVERIFY(t.proposal); - QCOMPARE(t.proposal->size(), hits.size()); - for (const QByteArray &hit : qAsConst(hits)) - QVERIFY(hasItem(t.proposal, hit)); -} - -} // namespace Tests -} // namespace Internal -} // namespace ClangCodeModel diff --git a/src/plugins/clangcodemodel/test/clangcodecompletion_test.h b/src/plugins/clangcodemodel/test/clangcodecompletion_test.h deleted file mode 100644 index ad2dd83ada2..00000000000 --- a/src/plugins/clangcodemodel/test/clangcodecompletion_test.h +++ /dev/null @@ -1,70 +0,0 @@ -/**************************************************************************** -** -** 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. -** -****************************************************************************/ - -#pragma once - -#include - -namespace ClangCodeModel { -namespace Internal { -namespace Tests { - -class ActivateClangModelManagerSupport; - -class ClangCodeCompletionTest : public QObject -{ - Q_OBJECT - -private slots: - void initTestCase(); - - void testCompleteDoxygenKeywords(); - void testCompletePreprocessorKeywords(); - void testCompleteIncludeDirective(); - - void testCompleteGlobals(); - void testCompleteMembers(); - void testCompleteMembersFromInside(); - void testCompleteMembersFromOutside(); - void testCompleteMembersFromFriend(); - void testCompleteFunctions(); - void testCompleteOverloads(); - void testCompleteConstructor(); - void testCompleteClassAndConstructor(); - - void testCompleteWithDotToArrowCorrection(); - void testDontCompleteWithDotToArrowCorrectionForFloats(); - - void testCompleteProjectDependingCode(); - void testCompleteProjectDependingCodeAfterChangingProject(); - void testCompleteProjectDependingCodeInGeneratedUiFile(); - - void testSignalCompletion_data(); - void testSignalCompletion(); -}; - -} // namespace Tests -} // namespace Internal -} // namespace ClangCodeModel diff --git a/src/plugins/clangcodemodel/test/clangdtests.cpp b/src/plugins/clangcodemodel/test/clangdtests.cpp index e22f2dc6fff..779b5ee9552 100644 --- a/src/plugins/clangcodemodel/test/clangdtests.cpp +++ b/src/plugins/clangcodemodel/test/clangdtests.cpp @@ -25,7 +25,6 @@ #include "clangdtests.h" -#include "clangautomationutils.h" #include "clangbatchfileprocessor.h" #include "../clangdclient.h" #include "../clangmodelmanagersupport.h" @@ -83,6 +82,11 @@ namespace ClangCodeModel { namespace Internal { namespace Tests { +static QString qrcPath(const QByteArray &relativeFilePath) +{ + return QLatin1String(":/unittests/ClangCodeModel/") + QString::fromUtf8(relativeFilePath); +} + ClangdTest::~ClangdTest() { EditorManager::closeAllEditors(false); diff --git a/src/plugins/cppeditor/cppmodelmanager.cpp b/src/plugins/cppeditor/cppmodelmanager.cpp index 7a17386ba44..1ab7d1b3b37 100644 --- a/src/plugins/cppeditor/cppmodelmanager.cpp +++ b/src/plugins/cppeditor/cppmodelmanager.cpp @@ -1653,12 +1653,12 @@ void CppModelManager::activateClangCodeModel( CppCompletionAssistProvider *CppModelManager::completionAssistProvider() const { - return d->m_activeModelManagerSupport->completionAssistProvider(); + return d->m_builtinModelManagerSupport->completionAssistProvider(); } CppCompletionAssistProvider *CppModelManager::functionHintAssistProvider() const { - return d->m_activeModelManagerSupport->functionHintAssistProvider(); + return d->m_builtinModelManagerSupport->functionHintAssistProvider(); } TextEditor::BaseHoverHandler *CppModelManager::createHoverHandler() const diff --git a/tests/unit/unittest/CMakeLists.txt b/tests/unit/unittest/CMakeLists.txt index e80672a33a4..649dd3fa036 100644 --- a/tests/unit/unittest/CMakeLists.txt +++ b/tests/unit/unittest/CMakeLists.txt @@ -174,14 +174,12 @@ extend_qtc_test(unittest DEFINES CLANG_UNIT_TESTS DEPENDS libclang SOURCES - activationsequencecontextprocessor-test.cpp activationsequenceprocessor-test.cpp chunksreportedmonitor.cpp clangasyncjob-base.cpp clangcodecompleteresults-test.cpp clangcodemodelserver-test.cpp clangcompletecodejob-test.cpp - clangcompletioncontextanalyzer-test.cpp clangdocumentprocessors-test.cpp clangdocumentprocessor-test.cpp clangdocuments-test.cpp @@ -205,7 +203,6 @@ extend_qtc_test(unittest clangupdateannotationsjob-test.cpp codecompleter-test.cpp codecompletionsextractor-test.cpp - completionchunkstotextconverter-test.cpp cursor-test.cpp diagnosticset-test.cpp diagnostic-test.cpp @@ -415,10 +412,7 @@ extend_qtc_test(unittest DEPENDS Utils CPlusPlus ClangSupport) extend_qtc_test(unittest SOURCES_PREFIX ../../../src/plugins/clangcodemodel SOURCES - clangactivationsequencecontextprocessor.cpp clangactivationsequencecontextprocessor.h clangactivationsequenceprocessor.cpp clangactivationsequenceprocessor.h - clangcompletionchunkstotextconverter.cpp clangcompletionchunkstotextconverter.h - clangcompletioncontextanalyzer.cpp clangcompletioncontextanalyzer.h clangfixitoperation.cpp clangfixitoperation.h clanguiheaderondiskmanager.cpp clanguiheaderondiskmanager.h ) diff --git a/tests/unit/unittest/activationsequencecontextprocessor-test.cpp b/tests/unit/unittest/activationsequencecontextprocessor-test.cpp deleted file mode 100644 index 84c2e87c76b..00000000000 --- a/tests/unit/unittest/activationsequencecontextprocessor-test.cpp +++ /dev/null @@ -1,221 +0,0 @@ -/**************************************************************************** -** -** 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 "googletest.h" - -#include - -#include - -#include - -#include -#include - -namespace { - -using ContextProcessor = ClangCodeModel::Internal::ActivationSequenceContextProcessor; -using TextEditor::AssistInterface; -using ClangCodeModel::Internal::ClangCompletionAssistInterface; - -TEST(ActivationSequenceContextProcessorSlowTest, TextCursorPosition) -{ - ClangCompletionAssistInterface interface("foobar", 4); - ContextProcessor processor{&interface}; - - ASSERT_THAT(processor.textCursor_forTestOnly().position(), 0); -} - -TEST(ActivationSequenceContextProcessor, StringLiteral) -{ - ClangCompletionAssistInterface interface("auto foo = \"bar\"", 12); - ContextProcessor processor{&interface}; - - ASSERT_THAT(processor.completionKind(), CPlusPlus::T_EOF_SYMBOL); -} - -TEST(ActivationSequenceContextProcessor, EndOfStringLiteral) -{ - ClangCompletionAssistInterface interface("auto foo = \"bar\"", 16); - ContextProcessor processor{&interface}; - - ASSERT_THAT(processor.completionKind(), CPlusPlus::T_EOF_SYMBOL); -} - -TEST(ActivationSequenceContextProcessor, FunctionCallComma) -{ - ClangCompletionAssistInterface interface("f(x, ", 4); - ContextProcessor processor{&interface}; - - ASSERT_THAT(processor.completionKind(), CPlusPlus::T_COMMA); -} - -TEST(ActivationSequenceContextProcessor, NonFunctionCallComma) -{ - ClangCompletionAssistInterface interface("int x, ", 6); - ContextProcessor processor{&interface}; - - ASSERT_THAT(processor.completionKind(), CPlusPlus::T_EOF_SYMBOL); -} - -TEST(ActivationSequenceContextProcessor, DoxygenComment) -{ - ClangCompletionAssistInterface interface("//! @", 5); - ContextProcessor processor{&interface}; - - ASSERT_THAT(processor.completionKind(), CPlusPlus::T_DOXY_COMMENT); -} - -TEST(ActivationSequenceContextProcessor, NonDoxygenComment) -{ - ClangCompletionAssistInterface interface("// @", 4); - ContextProcessor processor{&interface}; - - ASSERT_THAT(processor.completionKind(), CPlusPlus::T_EOF_SYMBOL); -} - -TEST(ActivationSequenceContextProcessor, Comment) -{ - ClangCompletionAssistInterface interface("//", 2); - ContextProcessor processor{&interface}; - - ASSERT_THAT(processor.completionKind(), CPlusPlus::T_EOF_SYMBOL); -} - -TEST(ActivationSequenceContextProcessor, InsideALiteral) -{ - ClangCompletionAssistInterface interface("\"foo\"", 2); - ContextProcessor processor{&interface}; - - ASSERT_THAT(processor.completionKind(), CPlusPlus::T_EOF_SYMBOL); -} - -TEST(ActivationSequenceContextProcessor, ShlashInsideAString) -{ - ClangCompletionAssistInterface interface("\"foo/bar\"", 5); - ContextProcessor processor{&interface}; - - ASSERT_THAT(processor.completionKind(), CPlusPlus::T_EOF_SYMBOL); -} - -TEST(ActivationSequenceContextProcessor, ShlashOutsideAString) -{ - ClangCompletionAssistInterface interface("foo/bar", 4); - ContextProcessor processor{&interface}; - - ASSERT_THAT(processor.completionKind(), CPlusPlus::T_EOF_SYMBOL); -} - -TEST(ActivationSequenceContextProcessor, FunctionLeftParen) -{ - ClangCompletionAssistInterface interface("foo(", 4); - ContextProcessor processor{&interface}; - - ASSERT_THAT(processor.completionKind(), CPlusPlus::T_LPAREN); -} - -TEST(ActivationSequenceContextProcessor, TemplateFunctionLeftParen) -{ - ClangCompletionAssistInterface interface("foo(", 7); - ContextProcessor processor{&interface}; - - ASSERT_THAT(processor.completionKind(), CPlusPlus::T_LPAREN); -} - -TEST(ActivationSequenceContextProcessor, TemplateFunctionSecondParameter) -{ - ClangCompletionAssistInterface interface("foo(", 7); - int startOfname = ContextProcessor::findStartOfName(interface.textDocument(), - 6, - ContextProcessor::NameCategory::Function); - - ASSERT_THAT(startOfname, 0); -} - -TEST(ActivationSequenceContextProcessor, ExpressionLeftParen) -{ - ClangCompletionAssistInterface interface("x * (", 5); - ContextProcessor processor{&interface}; - - ASSERT_THAT(processor.completionKind(), CPlusPlus::T_EOF_SYMBOL); -} - -TEST(ActivationSequenceContextProcessor, AngleInclude) -{ - ClangCompletionAssistInterface interface("#include ", 10); - ContextProcessor processor{&interface}; - - ASSERT_THAT(processor.completionKind(), CPlusPlus::T_ANGLE_STRING_LITERAL); -} - -TEST(ActivationSequenceContextProcessor, SlashInclude) -{ - ClangCompletionAssistInterface interface("#include ", 14); - ContextProcessor processor{&interface}; - - ASSERT_THAT(processor.completionKind(), CPlusPlus::T_SLASH); -} - -TEST(ActivationSequenceContextProcessor, QuoteInclude) -{ - ClangCompletionAssistInterface interface("#include \"foo/bar\"", 10); - ContextProcessor processor{&interface}; - - ASSERT_THAT(processor.completionKind(), CPlusPlus::T_STRING_LITERAL); -} - -TEST(ActivationSequenceContextProcessor, SlashInExlude) -{ - ClangCompletionAssistInterface interface("#exclude ", 14); - ContextProcessor processor{&interface}; - - ASSERT_THAT(processor.completionKind(), CPlusPlus::T_EOF_SYMBOL); -} - -TEST(ActivationSequenceContextProcessor, QuoteExclude) -{ - ClangCompletionAssistInterface interface("#exclude \"foo/bar\"", 10); - ContextProcessor processor{&interface}; - - ASSERT_THAT(processor.completionKind(), CPlusPlus::T_EOF_SYMBOL); -} - -TEST(ActivationSequenceContextProcessor, SkipeWhiteSpacesBeforeCursor) -{ - ClangCompletionAssistInterface interface("x-> ", 7); - ContextProcessor processor{&interface}; - - ASSERT_THAT(processor.completionKind(), CPlusPlus::T_ARROW); -} - -TEST(ActivationSequenceContextProcessor, SkipIdentifier) -{ - ClangCompletionAssistInterface interface("x->foo_", 7); - ContextProcessor processor{&interface}; - - ASSERT_THAT(processor.completionKind(), CPlusPlus::T_ARROW); -} - -} diff --git a/tests/unit/unittest/clangcompletioncontextanalyzer-test.cpp b/tests/unit/unittest/clangcompletioncontextanalyzer-test.cpp deleted file mode 100644 index 66ed01b19db..00000000000 --- a/tests/unit/unittest/clangcompletioncontextanalyzer-test.cpp +++ /dev/null @@ -1,589 +0,0 @@ -/**************************************************************************** -** -** 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 "googletest.h" - -#include -#include - -#include - -#include - -namespace ClangCodeModel { -namespace Internal { - -void PrintTo(const ClangCompletionContextAnalyzer::CompletionAction &completionAction, - ::std::ostream* os) -{ - using CCA = ClangCompletionContextAnalyzer; - - switch (completionAction) { - case CCA::PassThroughToLibClang: *os << "PassThroughToLibClang"; break; - case CCA::PassThroughToLibClangAfterLeftParen: *os << "PassThroughToLibClangAfterLeftParen"; break; - case CCA::CompleteDoxygenKeyword: *os << "CompleteDoxygenKeyword"; break; - case CCA::CompleteIncludePath: *os << "CompleteIncludePath"; break; - case CCA::CompletePreprocessorDirective: *os << "CompletePreprocessorDirective"; break; - case CCA::CompleteSignal: *os << "CompleteSignal"; break; - case CCA::CompleteSlot: *os << "CompleteSlot"; break; - case CCA::CompleteNone: *os << "CompleteNone"; break; - } -} - -} // Internal -} // ClangCodeModel - -namespace { - -using ::testing::PrintToString; -using ClangCodeModel::Internal::ClangCompletionAssistInterface; -using CCA = ClangCodeModel::Internal::ClangCompletionContextAnalyzer; - -class TestDocument -{ -public: - TestDocument(const QByteArray &theSource) - : source(theSource), - position(theSource.lastIndexOf('@')) // Use 'lastIndexOf' due to doxygen: "//! @keyword" - { - source.remove(position, 1); - } - - QByteArray source; - int position; -}; - -bool isPassThrough(CCA::CompletionAction completionAction) -{ - return completionAction != CCA::PassThroughToLibClang - && completionAction != CCA::PassThroughToLibClangAfterLeftParen; -} - -MATCHER(IsPassThroughToClang, std::string(negation ? "isn't" : "is") + " passed through to Clang") -{ - const auto completionAction = arg.completionAction(); - if (isPassThrough(completionAction)) { - *result_listener << "completion action is " << PrintToString(completionAction); - return false; - } - - return true; -} - -// Offsets are relative to positionInText -MATCHER_P5(HasResult, - completionAction, - positionForClangOffset, - positionForProposalOffset, - positionInText, - addSnippets, - std::string(negation ? "hasn't" : "has") - + " result of completion action " + PrintToString(completionAction) - + " and offset for clang " + PrintToString(positionForClangOffset) - + " and offset for proprosal " + PrintToString(positionForProposalOffset) - + " and addSnippets " + PrintToString(addSnippets)) -{ - const int actualPositionForClangOffset = arg.positionForClang() - positionInText; - const int actualPositionForProposalOffset = arg.positionForProposal() - positionInText; - - if (arg.completionAction() != completionAction - || actualPositionForClangOffset != positionForClangOffset - || actualPositionForProposalOffset != positionForProposalOffset - || addSnippets != arg.addSnippets()) { - *result_listener << "completion action is " << PrintToString(arg.completionAction()) - << " and offset for clang is " << PrintToString(actualPositionForClangOffset) - << " and offset for proprosal is " << PrintToString(actualPositionForProposalOffset) - << " and addSnippets is " << PrintToString(arg.addSnippets()); - return false; - } - - return true; -} - -// Offsets are relative to positionInText -MATCHER_P5(HasResultWithoutClangDifference, - completionAction, - positionForClangOffset, - positionForProposalOffset, - positionInText, - addSnippets, - std::string(negation ? "hasn't" : "has") - + " result of completion action " + PrintToString(completionAction) - + " and offset for clang " + PrintToString(positionForClangOffset) - + " and offset for proprosal " + PrintToString(positionForProposalOffset) - + " and addSnippets " + PrintToString(addSnippets)) -{ - const int actualPositionForProposalOffset = arg.positionForProposal() - positionInText; - - if (arg.completionAction() != completionAction - || arg.positionForClang() != positionForClangOffset - || actualPositionForProposalOffset != positionForProposalOffset - || addSnippets != arg.addSnippets()) { - *result_listener << "completion action is " << PrintToString(arg.completionAction()) - << " and offset for clang is " << PrintToString(arg.positionForClang()) - << " and offset for proprosal is " << PrintToString(actualPositionForProposalOffset) - << " and addSnippets is " << PrintToString(arg.addSnippets()); - return false; - } - - return true; -} - -class ClangCompletionContextAnalyzer : public ::testing::Test -{ -protected: - CCA runAnalyzer(const char *text); - -protected: - int positionInText = 0; -}; - -CCA ClangCompletionContextAnalyzer::runAnalyzer(const char *text) -{ - const TestDocument testDocument(text); - ClangCompletionAssistInterface assistInterface(testDocument.source, testDocument.position); - CCA analyzer(&assistInterface, CPlusPlus::LanguageFeatures::defaultFeatures()); - - positionInText = testDocument.position; - - analyzer.analyze(); - - return analyzer; -} - -TEST_F(ClangCompletionContextAnalyzer, WordsBeforeCursor) -{ - auto analyzer = runAnalyzer("foo bar@"); - - ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClang, -3, -3, positionInText, true)); -} - -TEST_F(ClangCompletionContextAnalyzer, AfterSpace) -{ - auto analyzer = runAnalyzer("foo @"); - - ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClang, 0, 0, positionInText, true)); -} - -TEST_F(ClangCompletionContextAnalyzer, AfterQualification) -{ - auto analyzer = runAnalyzer(" Foo::@"); - - ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClang, 0, 0, positionInText, false)); -} - -TEST_F(ClangCompletionContextAnalyzer, AtEndOfDotMember) -{ - auto analyzer = runAnalyzer("o.mem@"); - - ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClang, -3, -3, positionInText, false)); -} - -TEST_F(ClangCompletionContextAnalyzer, AtEndOfDotMemberWithSpaceInside) -{ - auto analyzer = runAnalyzer("o. mem@"); - - ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClang, -3, -3, positionInText, false)); -} - -TEST_F(ClangCompletionContextAnalyzer, AtBeginOfDotMember) -{ - auto analyzer = runAnalyzer("o.@mem"); - - ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClang, 0, 0, positionInText, false)); -} - -TEST_F(ClangCompletionContextAnalyzer, AtBeginOfDotMemberWithSpaceInside) -{ - auto analyzer = runAnalyzer("o. @mem"); - - ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClang, 0, 0, positionInText, false)); -} - -TEST_F(ClangCompletionContextAnalyzer, AtEndOfArrow) -{ - auto analyzer = runAnalyzer("o->mem@"); - - ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClang, -3, -3, positionInText, false)); -} - -TEST_F(ClangCompletionContextAnalyzer, AtEndOfArrowWithSpaceInside) -{ - auto analyzer = runAnalyzer("o-> mem@"); - - ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClang, -3, -3, positionInText, false)); -} - -TEST_F(ClangCompletionContextAnalyzer, AtBeginOfArrow) -{ - auto analyzer = runAnalyzer("o->@mem"); - - ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClang, 0, 0, positionInText, false)); -} - -TEST_F(ClangCompletionContextAnalyzer, AtBeginOfArrowWithSpaceInside) -{ - auto analyzer = runAnalyzer("o-> @mem"); - - ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClang, 0, 0, positionInText, false)); -} - -TEST_F(ClangCompletionContextAnalyzer, ArgumentOneAtCall) -{ - auto analyzer = runAnalyzer("f(@"); - - ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClangAfterLeftParen, 0, 0, positionInText, false)); -} - -TEST_F(ClangCompletionContextAnalyzer, ArgumentTwoAtCall) -{ - auto analyzer = runAnalyzer("f(1,@"); - - ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClangAfterLeftParen, 0, -2, positionInText, false)); -} - -TEST_F(ClangCompletionContextAnalyzer, ArgumentTwoWithSpaceAtCall) -{ - auto analyzer = runAnalyzer("f(1, @"); - - ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClangAfterLeftParen, 0, -3, positionInText, false)); -} - -TEST_F(ClangCompletionContextAnalyzer, WhitespaceAfterFunctionName) -{ - auto analyzer = runAnalyzer("foo (@"); - - ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClangAfterLeftParen, 0, 0, positionInText, false)); -} - -TEST_F(ClangCompletionContextAnalyzer, ConstructorCallWithBraceInitializer) -{ - auto analyzer = runAnalyzer("f{@"); - - ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClangAfterLeftParen, 0, 0, positionInText, false)); -} - -TEST_F(ClangCompletionContextAnalyzer, ArgumentTwoWithSpaceAtConstructorCallWithBraceInitializer) -{ - auto analyzer = runAnalyzer("f{1, @"); - - ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClangAfterLeftParen, 0, -3, positionInText, false)); -} - -TEST_F(ClangCompletionContextAnalyzer, WhitespaceBeforeConstructorCallWithBraceInitializer) -{ - auto analyzer = runAnalyzer("foo {@"); - - ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClangAfterLeftParen, 0, 0, positionInText, false)); -} - -TEST_F(ClangCompletionContextAnalyzer, OpenFunctionScopeNotAConstructor) -{ - auto analyzer = runAnalyzer("foo() {@"); - - ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClang, 0, 0, positionInText, true)); -} - -TEST_F(ClangCompletionContextAnalyzer, AfterOpeningParenthesis) -{ - auto analyzer = runAnalyzer("(@"); - - ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClang, 0, 0, positionInText, true)); -} - -TEST_F(ClangCompletionContextAnalyzer, AfterOpeningBraceAndIdentifierOnNewLine) -{ - auto analyzer = runAnalyzer("if (1) {\n" - "cla@"); - - ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClang, -3, -3, positionInText, true)); -} - -TEST_F(ClangCompletionContextAnalyzer, ArgumentOneAtSignal) -{ - auto analyzer = runAnalyzer("SIGNAL(@"); - - ASSERT_THAT(analyzer, HasResult(CCA::CompleteSignal, 0, 0, positionInText, false)); -} - -TEST_F(ClangCompletionContextAnalyzer, ArgumentOneWithLettersAtSignal) -{ - auto analyzer = runAnalyzer("SIGNAL(foo@"); - - ASSERT_THAT(analyzer, HasResult(CCA::CompleteSignal, -3, -3, positionInText, false)); -} - -TEST_F(ClangCompletionContextAnalyzer, ArgumentOneAtSlot) -{ - auto analyzer = runAnalyzer("SLOT(@"); - - ASSERT_THAT(analyzer, HasResult(CCA::CompleteSlot, -0, 0, positionInText, false)); -} - -TEST_F(ClangCompletionContextAnalyzer, ArgumentOneWithLettersAtSlot) -{ - auto analyzer = runAnalyzer("SLOT(foo@"); - - ASSERT_THAT(analyzer, HasResult(CCA::CompleteSlot, -3, -3, positionInText, false)); -} - -TEST_F(ClangCompletionContextAnalyzer, DoxygenWithBackslash) -{ - auto analyzer = runAnalyzer("//! \\@"); - - ASSERT_THAT(analyzer, HasResultWithoutClangDifference(CCA::CompleteDoxygenKeyword, -1, 0, positionInText, false)); -} - -TEST_F(ClangCompletionContextAnalyzer, DoxygenWithAt) -{ - auto analyzer = runAnalyzer("//! @@"); - - ASSERT_THAT(analyzer, HasResultWithoutClangDifference(CCA::CompleteDoxygenKeyword, -1, 0, positionInText, false)); -} - -TEST_F(ClangCompletionContextAnalyzer, DoxygenWithParameter) -{ - auto analyzer = runAnalyzer("//! \\par@"); - - ASSERT_THAT(analyzer, HasResultWithoutClangDifference(CCA::CompleteDoxygenKeyword, -1, -3, positionInText, false)); -} - -TEST_F(ClangCompletionContextAnalyzer, Preprocessor) -{ - auto analyzer = runAnalyzer("#@"); - - ASSERT_THAT(analyzer, HasResultWithoutClangDifference(CCA::CompletePreprocessorDirective, -1, 0, positionInText, false)); -} - -TEST_F(ClangCompletionContextAnalyzer, PreprocessorIf) -{ - auto analyzer = runAnalyzer("#if@"); - - ASSERT_THAT(analyzer, HasResultWithoutClangDifference(CCA::CompletePreprocessorDirective, -1, -2, positionInText, false)); -} - -TEST_F(ClangCompletionContextAnalyzer, LocalInclude) -{ - auto analyzer = runAnalyzer("#include \"foo@\""); - - ASSERT_THAT(analyzer, HasResultWithoutClangDifference(CCA::CompleteIncludePath, -1, -3, positionInText, false)); -} - -TEST_F(ClangCompletionContextAnalyzer, GlobalInclude) -{ - auto analyzer = runAnalyzer("#include "); - - ASSERT_THAT(analyzer, HasResultWithoutClangDifference(CCA::CompleteIncludePath, -1, -3, positionInText, false)); -} - -TEST_F(ClangCompletionContextAnalyzer, GlocalIncludeWithDirectory) -{ - auto analyzer = runAnalyzer("#include "); - - ASSERT_THAT(analyzer, HasResultWithoutClangDifference(CCA::CompleteIncludePath, -1, 0, positionInText, false)); -} - -TEST_F(ClangCompletionContextAnalyzer, AfterQuote) -{ - auto analyzer = runAnalyzer("\"@"); - - ASSERT_THAT(analyzer, IsPassThroughToClang()); -} - -TEST_F(ClangCompletionContextAnalyzer, AfterSpaceQuote) -{ - auto analyzer = runAnalyzer(" \"@"); - - ASSERT_THAT(analyzer, IsPassThroughToClang()); -} - -TEST_F(ClangCompletionContextAnalyzer, AfterQuotedText) -{ - auto analyzer = runAnalyzer("\"text\"@"); - - ASSERT_THAT(analyzer, IsPassThroughToClang()); -} - -TEST_F(ClangCompletionContextAnalyzer, InQuotedText) -{ - auto analyzer = runAnalyzer("\"hello cruel@ world\""); - - ASSERT_THAT(analyzer, IsPassThroughToClang()); -} - -TEST_F(ClangCompletionContextAnalyzer, SingleQuote) -{ - auto analyzer = runAnalyzer("'@'"); - - ASSERT_THAT(analyzer, IsPassThroughToClang()); -} - -TEST_F(ClangCompletionContextAnalyzer, AfterLetterInSingleQuoted) -{ - auto analyzer = runAnalyzer("'a@'"); - - ASSERT_THAT(analyzer, IsPassThroughToClang()); -} - -TEST_F(ClangCompletionContextAnalyzer, CommaOperator) -{ - auto analyzer = runAnalyzer("a = b,@\""); - - ASSERT_THAT(analyzer, IsPassThroughToClang()); -} - -TEST_F(ClangCompletionContextAnalyzer, DoxygenMarkerInNonDoxygenComment) -{ - auto analyzer = runAnalyzer("@@"); - - ASSERT_THAT(analyzer, IsPassThroughToClang()); -} - -TEST_F(ClangCompletionContextAnalyzer, DoxygenMarkerInNonDoxygenComment2) -{ - auto analyzer = runAnalyzer("\\@"); - - ASSERT_THAT(analyzer, IsPassThroughToClang()); -} - -TEST_F(ClangCompletionContextAnalyzer, AtEndOfOneLineComment) -{ - auto analyzer = runAnalyzer("// comment@"); - - ASSERT_THAT(analyzer, IsPassThroughToClang()); -} - -TEST_F(ClangCompletionContextAnalyzer, AfterOneLineCommentLine) -{ - auto analyzer = runAnalyzer("// comment\n" - "@"); - - ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClang, 0, 0, positionInText, true)); -} - -TEST_F(ClangCompletionContextAnalyzer, AfterEmptyOneLineComment) -{ - auto analyzer = runAnalyzer("//\n" - "@"); - - ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClang, 0, 0, positionInText, true)); -} - -TEST_F(ClangCompletionContextAnalyzer, AfterOneLineDoxygenComment1) -{ - auto analyzer = runAnalyzer("/// comment\n" - "@"); - - ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClang, 0, 0, positionInText, true)); -} - -TEST_F(ClangCompletionContextAnalyzer, AfterOneLineDoxygenComment2) -{ - auto analyzer = runAnalyzer("//! comment \n" - "@"); - - ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClang, 0, 0, positionInText, true)); -} - -TEST_F(ClangCompletionContextAnalyzer, BeginEndComment) -{ - auto analyzer = runAnalyzer("/* text@ */"); - - ASSERT_THAT(analyzer, IsPassThroughToClang()); -} - -TEST_F(ClangCompletionContextAnalyzer, Slash) -{ - auto analyzer = runAnalyzer("5 /@"); - - ASSERT_THAT(analyzer, IsPassThroughToClang()); -} - -TEST_F(ClangCompletionContextAnalyzer, LeftParen) -{ - auto analyzer = runAnalyzer("(@"); - - ASSERT_THAT(analyzer, IsPassThroughToClang()); -} - -TEST_F(ClangCompletionContextAnalyzer, TwoLeftParen) -{ - auto analyzer = runAnalyzer("((@"); - - ASSERT_THAT(analyzer, IsPassThroughToClang()); -} - -TEST_F(ClangCompletionContextAnalyzer, AsteriskLeftParen) -{ - auto analyzer = runAnalyzer("*(@"); - - ASSERT_THAT(analyzer, IsPassThroughToClang()); -} - -TEST_F(ClangCompletionContextAnalyzer, TemplatedFunctionSecondArgument) -{ - auto analyzer = runAnalyzer("f < decltype(bar -> member) > (1, @"); - - ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClangAfterLeftParen, 0, -3, positionInText, false)); -} - -TEST_F(ClangCompletionContextAnalyzer, FunctionNameStartPosition) -{ - auto analyzer = runAnalyzer(" f(1, @"); - int functionNameStartPosition = analyzer.functionNameStart(); - - ASSERT_THAT(functionNameStartPosition, 1); -} - -TEST_F(ClangCompletionContextAnalyzer, QualifiedFunctionNameStartPosition) -{ - auto analyzer = runAnalyzer(" Namespace::f(1, @"); - int functionNameStartPosition = analyzer.functionNameStart(); - - ASSERT_THAT(functionNameStartPosition, 1); -} - -TEST_F(ClangCompletionContextAnalyzer, SnippetsAfterOpeningBrace) -{ - auto analyzer = runAnalyzer("{@"); - - ASSERT_TRUE(analyzer.addSnippets()); -} - -TEST_F(ClangCompletionContextAnalyzer, NoSnippetsAfterFunctionCallLike_OpeningBrace) -{ - auto analyzer = runAnalyzer("foo{@"); - - ASSERT_FALSE(analyzer.addSnippets()); -} - -TEST_F(ClangCompletionContextAnalyzer, NoSnippetsAfterFunctionCallLike_OpeningParen) -{ - auto analyzer = runAnalyzer("foo(@"); - - ASSERT_FALSE(analyzer.addSnippets()); -} - -} // namespace diff --git a/tests/unit/unittest/completionchunkstotextconverter-test.cpp b/tests/unit/unittest/completionchunkstotextconverter-test.cpp deleted file mode 100644 index e54161f8363..00000000000 --- a/tests/unit/unittest/completionchunkstotextconverter-test.cpp +++ /dev/null @@ -1,379 +0,0 @@ -/**************************************************************************** -** -** 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 "googletest.h" - -#include -#include - -namespace { - -using ClangBackEnd::CodeCompletionChunk; -using ClangBackEnd::CodeCompletionChunks; -using Converter = ClangCodeModel::Internal::CompletionChunksToTextConverter; - -class CompletionChunksToTextConverter : public ::testing::Test -{ -protected: - Converter converter; - CodeCompletionChunk integerResultType{CodeCompletionChunk::ResultType, Utf8StringLiteral("int")}; - CodeCompletionChunk templateResultType{CodeCompletionChunk::ResultType, Utf8StringLiteral("Foo")}; - CodeCompletionChunk enumerationResultType{CodeCompletionChunk::ResultType, Utf8StringLiteral("Enumeration")}; - CodeCompletionChunk functionName{CodeCompletionChunk::TypedText, Utf8StringLiteral("Function")}; - CodeCompletionChunk namespaceName{CodeCompletionChunk::TypedText, Utf8StringLiteral("Namespace")}; - CodeCompletionChunk variableName{CodeCompletionChunk::TypedText, Utf8StringLiteral("Variable")}; - CodeCompletionChunk enumeratorName{CodeCompletionChunk::TypedText, Utf8StringLiteral("Enumerator")}; - CodeCompletionChunk enumerationName{CodeCompletionChunk::TypedText, Utf8StringLiteral("Enumeration")}; - CodeCompletionChunk className{CodeCompletionChunk::TypedText, Utf8StringLiteral("Class")}; - CodeCompletionChunk leftParen{CodeCompletionChunk::LeftParen, Utf8StringLiteral("(")}; - CodeCompletionChunk rightParen{CodeCompletionChunk::RightParen, Utf8StringLiteral(")")}; - CodeCompletionChunk comma{CodeCompletionChunk::Comma, Utf8StringLiteral(", ")}; - CodeCompletionChunk semicolon{CodeCompletionChunk::SemiColon, Utf8StringLiteral(";")}; - CodeCompletionChunk colonColonText{CodeCompletionChunk::Text, Utf8StringLiteral("::")}; - CodeCompletionChunk functionArgumentX{CodeCompletionChunk::Placeholder, Utf8StringLiteral("char x")}; - CodeCompletionChunk functionArgumentXAsCurrentParameter{CodeCompletionChunk::CurrentParameter, Utf8StringLiteral("char x")}; - CodeCompletionChunk functionArgumentY{CodeCompletionChunk::Placeholder, Utf8StringLiteral("int y")}; - CodeCompletionChunk functionArgumentYAsCurrentParamter{CodeCompletionChunk::CurrentParameter, Utf8StringLiteral("int y")}; - CodeCompletionChunk functionArgumentZ{CodeCompletionChunk::Placeholder, Utf8StringLiteral("int z")}; - CodeCompletionChunk functionArgumentTemplate{CodeCompletionChunk::Placeholder, Utf8StringLiteral("const Foo &foo")}; - CodeCompletionChunk switchName{CodeCompletionChunk::TypedText, Utf8StringLiteral("switch")}; - CodeCompletionChunk condition{CodeCompletionChunk::Placeholder, Utf8StringLiteral("condition")}; - CodeCompletionChunk leftBrace{CodeCompletionChunk::LeftBrace, Utf8StringLiteral("{")}; - CodeCompletionChunk rightBrace{CodeCompletionChunk::RightBrace, Utf8StringLiteral("}")}; - CodeCompletionChunk verticalSpace{CodeCompletionChunk::VerticalSpace, Utf8StringLiteral("\n")}; - CodeCompletionChunk throwName{CodeCompletionChunk::TypedText, Utf8StringLiteral("throw")}; - CodeCompletionChunk voidResultType{CodeCompletionChunk::ResultType, Utf8StringLiteral("void")}; - CodeCompletionChunk forName{CodeCompletionChunk::TypedText, Utf8StringLiteral("for")}; - CodeCompletionChunk initStatement{CodeCompletionChunk::Placeholder, Utf8StringLiteral("init-statement")}; - CodeCompletionChunk initExpression{CodeCompletionChunk::Placeholder, Utf8StringLiteral("init-expression")}; - CodeCompletionChunk statements{CodeCompletionChunk::Placeholder, Utf8StringLiteral("statements")}; - CodeCompletionChunk constCastName{CodeCompletionChunk::TypedText, Utf8StringLiteral("const_cast")}; - CodeCompletionChunk leftAngle{CodeCompletionChunk::LeftAngle, Utf8StringLiteral("<")}; - CodeCompletionChunk rightAngle{CodeCompletionChunk::RightAngle, Utf8StringLiteral(">")}; - CodeCompletionChunk elseName{CodeCompletionChunk::TypedText, Utf8StringLiteral("else")}; - CodeCompletionChunk ifName{CodeCompletionChunk::TypedText, Utf8StringLiteral("if")}; - CodeCompletionChunk horizontalSpace{CodeCompletionChunk::HorizontalSpace, Utf8StringLiteral(" ")}; - CodeCompletionChunk enableIfT{CodeCompletionChunk::TypedText, Utf8StringLiteral("enable_if_t")}; - CodeCompletionChunk enableIfTCondition{CodeCompletionChunk::Placeholder, Utf8StringLiteral("_Cond")}; - CodeCompletionChunk optionalEnableIfTType{CodeCompletionChunk::Placeholder, Utf8StringLiteral("_Tp"), true}; - CodeCompletionChunk optionalComma{CodeCompletionChunk::Comma, Utf8StringLiteral(", "), true}; - CodeCompletionChunk optionalFunctionArgumentY{CodeCompletionChunk::Placeholder, Utf8StringLiteral("int y"), true}; - CodeCompletionChunk optionalFunctionArgumentYAsCurrentParameter{CodeCompletionChunk::CurrentParameter, Utf8StringLiteral("int y"), true}; - CodeCompletionChunk optionalFunctionArgumentZ{CodeCompletionChunk::Placeholder, Utf8StringLiteral("int z"), true}; -}; - -TEST_F(CompletionChunksToTextConverter, ParseIsClearingText) -{ - CodeCompletionChunks completionChunks({integerResultType, functionName, leftParen, rightParen}); - converter.setAddResultType(true); - - converter.parseChunks(completionChunks); - - ASSERT_THAT(converter.text(), QStringLiteral("int Function()")); -} - -TEST_F(CompletionChunksToTextConverter, ConvertFunction) -{ - CodeCompletionChunks completionChunks({integerResultType, functionName, leftParen, rightParen}); - converter.setAddResultType(true); - - converter.parseChunks(completionChunks); - - ASSERT_THAT(converter.text(), QStringLiteral("int Function()")); -} - -TEST_F(CompletionChunksToTextConverter, ConvertFunctionWithParameters) -{ - CodeCompletionChunks completionChunks({integerResultType, functionName, leftParen, functionArgumentX,rightParen}); - converter.setAddResultType(true); - converter.setAddPlaceHolderText(true); - - converter.parseChunks(completionChunks); - - ASSERT_THAT(converter.text(), QStringLiteral("int Function(char x)")); -} - -TEST_F(CompletionChunksToTextConverter, ConvertToFunctionSignatureWithOneArgument) -{ - CodeCompletionChunks completionChunks({integerResultType, - functionName, - leftParen, - functionArgumentXAsCurrentParameter, - rightParen}); - - ASSERT_THAT(converter.convertToFunctionSignatureWithHtml( - completionChunks, - ClangBackEnd::CodeCompletion::FunctionCompletionKind), - QStringLiteral("int Function(char x)")); -} - -TEST_F(CompletionChunksToTextConverter, ConvertToFunctionSignatureWithOneParameterThatIsActive) -{ - CodeCompletionChunks completionChunks({integerResultType, - functionName, - leftParen, - functionArgumentXAsCurrentParameter, - rightParen}); - - ASSERT_THAT(converter.convertToFunctionSignatureWithHtml( - completionChunks, - ClangBackEnd::CodeCompletion::FunctionCompletionKind, - 1), - QStringLiteral("int Function(char x)")); -} - -TEST_F(CompletionChunksToTextConverter, ConvertToFunctionSignatureWithTwoParametersWhereOneIsActive) -{ - CodeCompletionChunks completionChunks({integerResultType, - functionName, - leftParen, - functionArgumentX, - comma, - functionArgumentYAsCurrentParamter, - rightParen}); - - ASSERT_THAT(converter.convertToFunctionSignatureWithHtml( - completionChunks, - ClangBackEnd::CodeCompletion::FunctionCompletionKind, - 2), - QStringLiteral("int Function(char x, int y)")); -} - -TEST_F(CompletionChunksToTextConverter, ConvertToFunctionSignatureWithTwoParametersWhereOneIsOptionalAndActive) -{ - CodeCompletionChunks completionChunks({integerResultType, - functionName, - leftParen, - functionArgumentX, - optionalComma, - optionalFunctionArgumentYAsCurrentParameter, - rightParen}); - - ASSERT_THAT(converter.convertToFunctionSignatureWithHtml( - completionChunks, - ClangBackEnd::CodeCompletion::FunctionCompletionKind, - 2), - QStringLiteral("int Function(char x, int y)")); -} - -TEST_F(CompletionChunksToTextConverter, ConvertToFunctionSignatureWithTemplateReturnType) -{ - CodeCompletionChunks completionChunks({templateResultType, - functionName, - leftParen, - functionArgumentX, - rightParen}); - - using ClangCodeModel::Internal::CompletionChunksToTextConverter; - - ASSERT_THAT(CompletionChunksToTextConverter::convertToFunctionSignatureWithHtml( - completionChunks, - ClangBackEnd::CodeCompletion::FunctionCompletionKind), - QStringLiteral("Foo<int> Function(char x)")); -} - -TEST_F(CompletionChunksToTextConverter, ConvertToFunctionSignatureWithTemplateArgument) -{ - CodeCompletionChunks completionChunks({integerResultType, - functionName, - leftParen, - functionArgumentTemplate, - rightParen}); - - using ClangCodeModel::Internal::CompletionChunksToTextConverter; - - ASSERT_THAT(CompletionChunksToTextConverter::convertToFunctionSignatureWithHtml( - completionChunks, - ClangBackEnd::CodeCompletion::FunctionCompletionKind), - QStringLiteral("int Function(const Foo<int> &foo)")); -} - -TEST_F(CompletionChunksToTextConverter, ConvertFunctionWithOptionalParameter) -{ - CodeCompletionChunks completionChunks({integerResultType, - functionName, - leftParen, - functionArgumentX, - optionalComma, - optionalFunctionArgumentY, - optionalComma, - optionalFunctionArgumentZ, - rightParen}); - - ASSERT_THAT(Converter::convertToToolTipWithHtml(completionChunks, - ClangBackEnd::CodeCompletion::FunctionCompletionKind), - QStringLiteral("int Function(char x, int y, int z)")); -} - -TEST_F(CompletionChunksToTextConverter, ConvertVariable) -{ - CodeCompletionChunks completionChunks({integerResultType, variableName}); - converter.setAddResultType(true); - - converter.parseChunks(completionChunks); - - ASSERT_THAT(converter.text(), QStringLiteral("int Variable")); -} - -TEST_F(CompletionChunksToTextConverter, Enumerator) -{ - CodeCompletionChunks completionChunks({enumerationResultType, enumeratorName}); - converter.setAddResultType(true); - - converter.parseChunks(completionChunks); - - ASSERT_THAT(converter.text(), QStringLiteral("Enumeration Enumerator")); -} - -TEST_F(CompletionChunksToTextConverter, Enumeration) -{ - CodeCompletionChunks completionChunks({className}); - - converter.parseChunks(completionChunks); - - ASSERT_THAT(converter.text(), QStringLiteral("Class")); -} - -TEST_F(CompletionChunksToTextConverter, SwitchAsKeyword) -{ - CodeCompletionChunks completionChunks({switchName, - leftParen, - condition, - rightParen, - leftBrace, - verticalSpace, - rightBrace}); - converter.setupForKeywords(); - - converter.parseChunks(completionChunks); - - ASSERT_THAT(converter.text(), QStringLiteral("switch () {\n\n}")); - ASSERT_THAT(converter.placeholderPositions().at(0), 8); -} - -TEST_F(CompletionChunksToTextConverter, SwitchAsName) -{ - CodeCompletionChunks completionChunks({switchName, - leftParen, - condition, - rightParen, - leftBrace, - verticalSpace, - rightBrace}); - - const QString text = ClangCodeModel::Internal::CompletionChunksToTextConverter::convertToName( - completionChunks); - - ASSERT_THAT(text, QStringLiteral("switch(){}")); -} - -TEST_F(CompletionChunksToTextConverter, For) -{ - CodeCompletionChunks completionChunks({forName, - leftParen, - initStatement, - semicolon, - initExpression, - semicolon, - condition, - rightParen, - leftBrace, - verticalSpace, - statements, - verticalSpace, - rightBrace}); - converter.setupForKeywords(); - - converter.parseChunks(completionChunks); - - ASSERT_THAT(converter.text(), QStringLiteral("for (;;) {\n\n}")); -} - -TEST_F(CompletionChunksToTextConverter, const_cast) -{ - CodeCompletionChunks completionChunks({constCastName, - leftAngle, - rightAngle, - leftParen, - rightParen}); - converter.setupForKeywords(); - - converter.parseChunks(completionChunks); - - ASSERT_THAT(converter.text(), QStringLiteral("const_cast<>()")); -} - -TEST_F(CompletionChunksToTextConverter, Throw) -{ - CodeCompletionChunks completionChunks({voidResultType, throwName}); - - auto completionName = Converter::convertToName(completionChunks); - - ASSERT_THAT(completionName, QStringLiteral("throw")); -} - -TEST_F(CompletionChunksToTextConverter, ElseIf) -{ - CodeCompletionChunks completionChunks({elseName, - horizontalSpace, - ifName, - horizontalSpace, - leftBrace, - verticalSpace, - statements, - verticalSpace, - rightBrace}); - converter.setupForKeywords(); - - converter.parseChunks(completionChunks); - - ASSERT_THAT(converter.text(), QStringLiteral("else if {\n\n}")); -} - -TEST_F(CompletionChunksToTextConverter, EnableIfT) -{ - CodeCompletionChunks completionChunks({enableIfT, - leftAngle, - enableIfTCondition, - optionalComma, - optionalEnableIfTType, - rightAngle}); - converter.setupForKeywords(); - - converter.parseChunks(completionChunks); - - ASSERT_THAT(converter.text(), QStringLiteral("enable_if_t<>")); -} - -TEST_F(CompletionChunksToTextConverter, Namespace) -{ - CodeCompletionChunks completionChunks({namespaceName, colonColonText}); - - converter.parseChunks(completionChunks); - - ASSERT_THAT(converter.text(), QStringLiteral("Namespace::")); -} - -} diff --git a/tests/unit/unittest/unittest.qbs b/tests/unit/unittest/unittest.qbs index a28943dd98c..32db4b010dc 100644 --- a/tests/unit/unittest/unittest.qbs +++ b/tests/unit/unittest/unittest.qbs @@ -193,7 +193,6 @@ Project { name: "libclang tests" condition: libclang.present && (!qbs.targetOS.contains("windows") || libclang.llvmBuildModeMatches) files: [ - "activationsequencecontextprocessor-test.cpp", "activationsequenceprocessor-test.cpp", "chunksreportedmonitor.cpp", "chunksreportedmonitor.h", @@ -203,7 +202,6 @@ Project { "clangcodemodelserver-test.cpp", "clangcompareoperators.h", "clangcompletecodejob-test.cpp", - "clangcompletioncontextanalyzer-test.cpp", "clangdocument-test.cpp", "clangdocumentprocessor-test.cpp", "clangdocumentprocessors-test.cpp", @@ -225,7 +223,6 @@ Project { "clangupdateannotationsjob-test.cpp", "codecompleter-test.cpp", "codecompletionsextractor-test.cpp", - "completionchunkstotextconverter-test.cpp", "cursor-test.cpp", "diagnostic-test.cpp", "diagnosticcontainer-matcher.h", @@ -392,14 +389,8 @@ Project { name: "sources from clangcodemodel" prefix: "../../../src/plugins/clangcodemodel/" files: [ - "clangactivationsequencecontextprocessor.cpp", - "clangactivationsequencecontextprocessor.h", "clangactivationsequenceprocessor.cpp", "clangactivationsequenceprocessor.h", - "clangcompletionchunkstotextconverter.cpp", - "clangcompletionchunkstotextconverter.h", - "clangcompletioncontextanalyzer.cpp", - "clangcompletioncontextanalyzer.h", "clangfixitoperation.cpp", "clangfixitoperation.h", "clanguiheaderondiskmanager.cpp",