From efc39304a1a18b815c968a4fee6c6d4b2651aac2 Mon Sep 17 00:00:00 2001 From: Ivan Donchevskii Date: Thu, 27 Sep 2018 15:50:12 +0200 Subject: [PATCH] Clang: Move the majority of completion items sorting to ClangBackend With this change ClangCodeModel only needs to sort completions by prefix. Also some other optimization have become possible and are implemented here: 1. Getting completions after '{' for constructor overloads by replacing it with '(' inside usaved file. 2. Checking for all overloads requires only previous item check because all Class completions are already sorted to go before all CXXConstructor completions. Since they are not mixed no extra search is required. Change-Id: Ie0187ad96a20857a63c1d71ddec74606b803f572 Reviewed-by: Nikolai Kosjar --- .../cplusplus/examples/tidy_example.cpp | 2 + .../clangassistproposalmodel.cpp | 6 +- .../clangcompletionassistprocessor.cpp | 104 ++++++------------ .../clangbackend/source/codecompleter.cpp | 51 ++++++--- .../source/codecompletionsextractor.cpp | 72 +++++++++++- .../source/codecompletionsextractor.h | 4 +- tests/unit/unittest/codecompleter-test.cpp | 99 +++++++++++++++-- .../codecompletionsextractor-test.cpp | 12 ++ .../unittest/data/complete_smartpointer.cpp | 7 +- .../unit/unittest/data/completions_order.cpp | 9 ++ 10 files changed, 262 insertions(+), 104 deletions(-) create mode 100644 tests/unit/unittest/data/completions_order.cpp diff --git a/share/qtcreator/cplusplus/examples/tidy_example.cpp b/share/qtcreator/cplusplus/examples/tidy_example.cpp index dc921114ea1..2b41a1e83b0 100644 --- a/share/qtcreator/cplusplus/examples/tidy_example.cpp +++ b/share/qtcreator/cplusplus/examples/tidy_example.cpp @@ -203,6 +203,8 @@ public: virtual bool check(bool enable = true); }; +bool Derived2:: + // performance-unnecessary-value-param void use(Base b) { diff --git a/src/plugins/clangcodemodel/clangassistproposalmodel.cpp b/src/plugins/clangcodemodel/clangassistproposalmodel.cpp index 148ebb0ad48..6e535fb04a7 100644 --- a/src/plugins/clangcodemodel/clangassistproposalmodel.cpp +++ b/src/plugins/clangcodemodel/clangassistproposalmodel.cpp @@ -56,11 +56,7 @@ void ClangAssistProposalModel::sort(const QString &/*prefix*/) return static_cast(first->prefixMatch()) < static_cast(second->prefixMatch()); } - if (first->requiresFixIts() != second->requiresFixIts()) - return first->requiresFixIts() < second->requiresFixIts(); - return (first->order() > 0 - && (first->order() < second->order() - || (first->order() == second->order() && first->text() < second->text()))); + return false; }; // Keep the order for the items with the same priority and name. diff --git a/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp b/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp index 843778e4bbe..e87135351db 100644 --- a/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp +++ b/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp @@ -51,8 +51,9 @@ #include #include -#include #include +#include +#include #include #include @@ -76,20 +77,18 @@ static void addAssistProposalItem(QList &items, 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) { - ClangBackEnd::CodeCompletionChunk resultType = codeCompletion.chunks.first(); auto *item = static_cast(sameItem); item->setHasOverloadsWithParameters(true); - if (resultType.kind != ClangBackEnd::CodeCompletionChunk::ResultType) { - // It's the constructor. + 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? - if (!item->firstCodeCompletion().hasParameters) - item->removeFirstCodeCompletion(); item->appendCodeCompletion(codeCompletion); return; } @@ -98,15 +97,27 @@ static void addFunctionOverloadAssistProposalItem(QListposition()); cursor.movePosition(QTextCursor::StartOfWord); + const ClangBackEnd::CodeCompletionChunk resultType = codeCompletion.chunks.first(); if (::Utils::Text::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.hasParameters + && completion.completionKind == lastItem->firstCodeCompletion().completionKind + && lastItem->text() == name; +} + static QList toAssistProposalItems( const CodeCompletions &completions, const ClangCompletionAssistInterface *interface) @@ -117,8 +128,9 @@ static QList toAssistProposalItems( QList items; items.reserve(completions.size()); for (const CodeCompletion &codeCompletion : completions) { - if (codeCompletion.text.isEmpty()) // TODO: Make isValid()? - continue; + if (codeCompletion.text.isEmpty()) + continue; // It's an OverloadCandidate which has text but no typedText. + if (signalCompletion && codeCompletion.completionKind != CodeCompletion::SignalCompletionKind) continue; if (slotCompletion && codeCompletion.completionKind != CodeCompletion::SlotCompletionKind) @@ -128,34 +140,16 @@ static QList toAssistProposalItems( ? CompletionChunksToTextConverter::convertToName(codeCompletion.chunks) : codeCompletion.text.toString(); - if (codeCompletion.completionKind == CodeCompletion::ConstructorCompletionKind - || codeCompletion.completionKind == CodeCompletion::ClassCompletionKind) { - auto samePreviousConstructor - = std::find_if(items.begin(), - items.end(), - [&](const AssistProposalItemInterface *item) { - return item->text() == name - && static_cast(item)->firstCodeCompletion() - .completionKind == codeCompletion.completionKind; - }); - if (samePreviousConstructor == items.end()) { - addAssistProposalItem(items, codeCompletion, name); - } else if (codeCompletion.completionKind == CodeCompletion::ConstructorCompletionKind){ - addFunctionOverloadAssistProposalItem(items, *samePreviousConstructor, interface, - codeCompletion, name); - } - continue; - } - - if (!items.empty() && items.last()->text() == name) { - if ((codeCompletion.completionKind == CodeCompletion::FunctionCompletionKind - || codeCompletion.completionKind == CodeCompletion::FunctionDefinitionCompletionKind) - && codeCompletion.hasParameters) { + if (items.empty()) { + addAssistProposalItem(items, codeCompletion, name); + } else { + auto *lastItem = static_cast(items.last()); + if (isTheSameFunctionOverload(codeCompletion, name, lastItem)) { addFunctionOverloadAssistProposalItem(items, items.back(), interface, codeCompletion, name); + } else { + addAssistProposalItem(items, codeCompletion, name); } - } else { - addAssistProposalItem(items, codeCompletion, name); } } @@ -187,48 +181,14 @@ IAssistProposal *ClangCompletionAssistProcessor::perform(const AssistInterface * return startCompletionHelper(); // == 0 if results are calculated asynchronously } -static CodeCompletions filterFunctionSignatures(const CodeCompletions &completions) -{ - return ::Utils::filtered(completions, [](const CodeCompletion &completion) { - return completion.completionKind == CodeCompletion::FunctionOverloadCompletionKind; - }); -} - -static CodeCompletions filterConstructorSignatures(Utf8String textBefore, - const CodeCompletions &completions) -{ - const int prevStatementEnd = textBefore.lastIndexOf(";"); - if (prevStatementEnd != -1) - textBefore = textBefore.mid(prevStatementEnd + 1); - - return ::Utils::filtered(completions, [&textBefore](const CodeCompletion &completion) { - if (completion.completionKind != CodeCompletion::ConstructorCompletionKind) - return false; - const Utf8String type = completion.chunks.at(0).text; - return textBefore.indexOf(type) != -1; - }); -} - -void ClangCompletionAssistProcessor::handleAvailableCompletions( - const CodeCompletions &completions) +void ClangCompletionAssistProcessor::handleAvailableCompletions(const CodeCompletions &completions) { QTC_CHECK(m_completions.isEmpty()); - if (m_sentRequestType == FunctionHintCompletion){ - CodeCompletions functionSignatures; - if (m_completionOperator == T_LPAREN) { - functionSignatures = filterFunctionSignatures(completions); - } else { - const QTextBlock block = m_interface->textDocument()->findBlock( - m_interface->position()); - const QString textBefore = block.text().left( - m_interface->position() - block.position()); - - functionSignatures = filterConstructorSignatures(textBefore, completions); - } - - if (!functionSignatures.isEmpty()) { - setAsyncProposalAvailable(createFunctionHintProposal(functionSignatures)); + if (m_sentRequestType == FunctionHintCompletion) { + const CodeCompletion &firstCompletion = completions.front(); + if (firstCompletion.completionKind == CodeCompletion::FunctionOverloadCompletionKind) { + setAsyncProposalAvailable(createFunctionHintProposal(completions)); return; } // else: Proceed with a normal completion in case: diff --git a/src/tools/clangbackend/source/codecompleter.cpp b/src/tools/clangbackend/source/codecompleter.cpp index 7a11ff02d8e..5520b5b3a9d 100644 --- a/src/tools/clangbackend/source/codecompleter.cpp +++ b/src/tools/clangbackend/source/codecompleter.cpp @@ -40,6 +40,8 @@ #include "unsavedfile.h" #include "unsavedfiles.h" +#include + #include namespace ClangBackEnd { @@ -47,13 +49,14 @@ namespace ClangBackEnd { namespace { CodeCompletions toCodeCompletions(const TranslationUnit &translationUnit, - const ClangCodeCompleteResults &results) + const ClangCodeCompleteResults &results, + bool onlyFunctionOverloads) { if (results.isNull()) return CodeCompletions(); CodeCompletionsExtractor extractor(translationUnit.cxTranslationUnit(), results.data()); - CodeCompletions codeCompletions = extractor.extractAll(); + CodeCompletions codeCompletions = extractor.extractAll(onlyFunctionOverloads); return codeCompletions; } @@ -83,33 +86,49 @@ CodeCompleter::CodeCompleter(const TranslationUnit &translationUnit, { } +static void replaceWithOpeningParen(UnsavedFile &file, uint line, uint column) +{ + bool ok; + const uint pos = file.toUtf8Position(line, column, &ok); + QTC_ASSERT(ok, return;); + file.replaceAt(pos, 1, Utf8String("(", 1)); +} + CodeCompletions CodeCompleter::complete(uint line, uint column, int funcNameStartLine, int funcNameStartColumn) { + if (funcNameStartLine >= 0) { + UnsavedFile &file = unsavedFiles.unsavedFile(translationUnit.filePath()); + // Replace '{' by '(' to get proper FunctionOverloadCompletionKind for constructor. + if (file.hasCharacterAt(line, column - 1, '{')) + replaceWithOpeningParen(file, line, column - 1); + } + // Check if we have a smart pointer completion and get proper constructor signatures in results. // Results are empty when it's not a smart pointer or this completion failed. - ClangCodeCompleteResults results = completeSmartPointerCreation(line, - column, - funcNameStartLine, - funcNameStartColumn); + ClangCodeCompleteResults clangCompletions = completeSmartPointerCreation(line, + column, + funcNameStartLine, + funcNameStartColumn); - if (results.isNull() || results.isEmpty()) - results = completeHelper(line, column); + // Default completion. + if (clangCompletions.isNull() || clangCompletions.isEmpty()) + clangCompletions = completeHelper(line, column); - filterUnknownContextResults(results, unsavedFile(), line, column); + filterUnknownContextResults(clangCompletions, unsavedFile(), line, column); - return toCodeCompletions(translationUnit, results); + return toCodeCompletions(translationUnit, clangCompletions, funcNameStartLine >= 0); } // For given "make_unique" / "make_shared" / "QSharedPointer::create" return "new T(" // Otherwize return empty QString -static QString tweakName(const QString &oldName) +static QString tweakName(const Utf8String &oldName) { - QString fullName = oldName.trimmed(); - if (!fullName.contains('>')) + if (!oldName.contains('>')) return QString(); + QString fullName = QString(oldName).trimmed(); if (!fullName.endsWith('>')) { // This is the class::method case - remove ::method part if (!fullName.endsWith("create") || !fullName.contains("QSharedPointer")) @@ -138,10 +157,12 @@ ClangCodeCompleteResults CodeCompleter::completeSmartPointerCreation(uint line, bool ok; const uint startPos = file.toUtf8Position(funcNameStartLine, funcNameStartColumn, &ok); + QTC_ASSERT(ok, return ClangCodeCompleteResults();); const uint endPos = file.toUtf8Position(line, column - 1, &ok); + QTC_ASSERT(ok, return ClangCodeCompleteResults();); - Utf8String content = file.fileContent(); - const QString oldName = content.mid(startPos, endPos - startPos); + const Utf8String content = file.fileContent(); + const Utf8String oldName = content.mid(startPos, endPos - startPos); const QString updatedName = tweakName(oldName); if (updatedName.isEmpty()) return ClangCodeCompleteResults(); diff --git a/src/tools/clangbackend/source/codecompletionsextractor.cpp b/src/tools/clangbackend/source/codecompletionsextractor.cpp index bd961dc4aa5..25be6bddcf3 100644 --- a/src/tools/clangbackend/source/codecompletionsextractor.cpp +++ b/src/tools/clangbackend/source/codecompletionsextractor.cpp @@ -27,9 +27,13 @@ #include "clangbackend_global.h" #include "clangstring.h" +#include "clangtranslationunit.h" #include "codecompletionchunkconverter.h" +#include "sourcelocation.h" #include "sourcerange.h" +#include + #include namespace ClangBackEnd { @@ -85,7 +89,7 @@ bool CodeCompletionsExtractor::peek(const Utf8String &name) return false; } -CodeCompletions CodeCompletionsExtractor::extractAll() +CodeCompletions CodeCompletionsExtractor::extractAll(bool onlyFunctionOverloads) { CodeCompletions codeCompletions; codeCompletions.reserve(int(cxCodeCompleteResults->NumResults)); @@ -93,9 +97,75 @@ CodeCompletions CodeCompletionsExtractor::extractAll() while (next()) codeCompletions.append(currentCodeCompletion_); + handleCompletions(codeCompletions, onlyFunctionOverloads); + return codeCompletions; } +static CodeCompletions filterFunctionOverloads(const CodeCompletions &completions) +{ + return ::Utils::filtered(completions, [](const CodeCompletion &completion) { + return completion.completionKind == CodeCompletion::FunctionOverloadCompletionKind; + }); +} + +static ::Utils::optional classBeforeCXXConstructor(const CodeCompletion &first, + const CodeCompletion &second) +{ + // Put ClassCompletionKind elements before ConstructorCompletionKind elements + // when they have the same name. + if (first.completionKind == CodeCompletion::ClassCompletionKind + && second.completionKind == CodeCompletion::ConstructorCompletionKind + && first.text == second.text) { + return true; + } + + if (first.completionKind == CodeCompletion::ConstructorCompletionKind + && second.completionKind == CodeCompletion::ClassCompletionKind + && first.text == second.text) { + return false; + } + + return ::Utils::optional(); +} + +static void sortCodeCompletions(CodeCompletions &codeCompletions) +{ + auto currentItemsCompare = [](const CodeCompletion &first, + const CodeCompletion &second) { + // Items without fix-its come first. + if (first.requiredFixIts.empty() != second.requiredFixIts.empty()) + return first.requiredFixIts.empty() > second.requiredFixIts.empty(); + + const ::Utils::optional classBeforeConstructorWithTheSameName + = classBeforeCXXConstructor(first, second); + if (classBeforeConstructorWithTheSameName) + return classBeforeConstructorWithTheSameName.value(); + + return (first.priority > 0 + && (first.priority < second.priority + || (first.priority == second.priority && first.text < second.text))); + }; + + // Keep the order for the items with the same priority and name. + std::stable_sort(codeCompletions.begin(), codeCompletions.end(), currentItemsCompare); +} + +void CodeCompletionsExtractor::handleCompletions(CodeCompletions &codeCompletions, + bool onlyFunctionOverloads) +{ + if (onlyFunctionOverloads) { + const CodeCompletions overloadCompletions = filterFunctionOverloads(codeCompletions); + + // If filtered completions are empty the assumption we need function overloads is wrong + // therefore we do not use filtered results in that case. + if (!overloadCompletions.isEmpty()) + codeCompletions = overloadCompletions; + } + + sortCodeCompletions(codeCompletions); +} + void CodeCompletionsExtractor::extractCompletionKind() { switch (currentCxCodeCompleteResult.CursorKind) { diff --git a/src/tools/clangbackend/source/codecompletionsextractor.h b/src/tools/clangbackend/source/codecompletionsextractor.h index 1c5f963c14b..928dabd25d3 100644 --- a/src/tools/clangbackend/source/codecompletionsextractor.h +++ b/src/tools/clangbackend/source/codecompletionsextractor.h @@ -50,7 +50,7 @@ public: bool next(); bool peek(const Utf8String &name); - CodeCompletions extractAll(); + CodeCompletions extractAll(bool onlyFunctionOverloads); const CodeCompletion ¤tCodeCompletion() const; @@ -73,6 +73,8 @@ private: void decreasePriorityForQObjectInternals(); void decreasePriorityForOperators(); + void handleCompletions(CodeCompletions &codeCompletions, bool onlyFunctionOverloads); + bool hasText(const Utf8String &text, CXCompletionString cxCompletionString) const; private: diff --git a/tests/unit/unittest/codecompleter-test.cpp b/tests/unit/unittest/codecompleter-test.cpp index 0a20849bb8f..f72a9eb8281 100644 --- a/tests/unit/unittest/codecompleter-test.cpp +++ b/tests/unit/unittest/codecompleter-test.cpp @@ -43,6 +43,7 @@ using ::testing::Not; using ::testing::PrintToString; using ClangBackEnd::CodeCompletion; +using ClangBackEnd::CodeCompletionChunk; using ClangBackEnd::CodeCompleter; namespace { @@ -65,6 +66,29 @@ MATCHER_P2(IsCodeCompletion, text, completionKind, return true; } +MATCHER_P(IsOverloadCompletion, text, + std::string(negation ? "isn't" : "is") + " overload completion with text " + PrintToString(text)) +{ + Utf8String overloadName; + for (auto &chunk : arg.chunks) { + if (chunk.kind == CodeCompletionChunk::Text) { + overloadName = chunk.text; + break; + } + } + if (overloadName != text) { + *result_listener << "text is " + PrintToString(overloadName) + " and not " + PrintToString(text); + return false; + } + + if (arg.completionKind != CodeCompletion::FunctionOverloadCompletionKind) { + *result_listener << "kind is " + PrintToString(arg.completionKind) + " and not " + PrintToString(CodeCompletion::FunctionOverloadCompletionKind); + return false; + } + + return true; +} + MATCHER(HasFixIts, "") { return !arg.requiredFixIts.empty(); @@ -195,6 +219,12 @@ protected: readFileContent("/complete_smartpointer.cpp"), true }; + ClangBackEnd::FileContainer completionsOrder{ + Utf8StringLiteral(TESTDATA_DIR"/completions_order.cpp"), + {includePathArgument}, + readFileContent("/completions_order.cpp"), + true + }; }; using CodeCompleterSlowTest = CodeCompleter; @@ -306,27 +336,24 @@ TEST_F(CodeCompleterSlowTest, UniquePointerCompletion) { auto myCompleter = setupCompleter(smartPointerCompletion); - ASSERT_THAT(myCompleter.complete(55, 54, 55, 32), - Contains(IsCodeCompletion(Utf8StringLiteral("Bar"), - CodeCompletion::ConstructorCompletionKind))); + ASSERT_THAT(myCompleter.complete(59, 54, 59, 32), + Contains(IsOverloadCompletion(Utf8StringLiteral("Bar")))); } TEST_F(CodeCompleterSlowTest, SharedPointerCompletion) { auto myCompleter = setupCompleter(smartPointerCompletion); - ASSERT_THAT(myCompleter.complete(56, 55, 56, 33), - Contains(IsCodeCompletion(Utf8StringLiteral("Bar"), - CodeCompletion::ConstructorCompletionKind))); + ASSERT_THAT(myCompleter.complete(60, 55, 60, 33), + Contains(IsOverloadCompletion(Utf8StringLiteral("Bar")))); } TEST_F(CodeCompleterSlowTest, QSharedPointerCompletion) { auto myCompleter = setupCompleter(smartPointerCompletion); - ASSERT_THAT(myCompleter.complete(57, 60, 57, 32), - Contains(IsCodeCompletion(Utf8StringLiteral("Bar"), - CodeCompletion::ConstructorCompletionKind))); + ASSERT_THAT(myCompleter.complete(61, 60, 61, 32), + Contains(IsOverloadCompletion(Utf8StringLiteral("Bar")))); } TEST_F(CodeCompleterSlowTest, FunctionInUnsavedIncludedHeader) @@ -499,6 +526,60 @@ TEST_F(CodeCompleterSlowTest, GlobalCompletionAfterForwardDeclaredClassPointer) ASSERT_TRUE(!completions.isEmpty()); } +TEST_F(CodeCompleterSlowTest, ConstructorCompletionExists) +{ + auto myCompleter = setupCompleter(completionsOrder); + const ClangBackEnd::CodeCompletions completions = myCompleter.complete(8, 1); + + int constructorIndex = Utils::indexOf(completions, [](const CodeCompletion &codeCompletion) { + return codeCompletion.text == "Constructor" && codeCompletion.completionKind == CodeCompletion::ConstructorCompletionKind; + }); + + ASSERT_THAT(constructorIndex != -1, true); +} + +TEST_F(CodeCompleterSlowTest, ClassConstructorCompletionsOrder) +{ + auto myCompleter = setupCompleter(completionsOrder); + const ClangBackEnd::CodeCompletions completions = myCompleter.complete(8, 1); + + int classIndex = Utils::indexOf(completions, [](const CodeCompletion &codeCompletion) { + return codeCompletion.text == "Constructor" && codeCompletion.completionKind == CodeCompletion::ClassCompletionKind; + }); + int constructorIndex = Utils::indexOf(completions, [](const CodeCompletion &codeCompletion) { + return codeCompletion.text == "Constructor" && codeCompletion.completionKind == CodeCompletion::ConstructorCompletionKind; + }); + + ASSERT_THAT(classIndex < constructorIndex, true); +} + +TEST_F(CodeCompleterSlowTest, SharedPointerCompletionsOrder) +{ + auto myCompleter = setupCompleter(smartPointerCompletion); + const ClangBackEnd::CodeCompletions completions = myCompleter.complete(62, 11); + + int resetIndex = Utils::indexOf(completions, [](const CodeCompletion &codeCompletion) { + return codeCompletion.text == "reset"; + }); + int barDestructorIndex = Utils::indexOf(completions, [](const CodeCompletion &codeCompletion) { + return codeCompletion.text == "~Bar"; + }); + + ASSERT_THAT(barDestructorIndex < resetIndex, true); +} + +TEST_F(CodeCompleterSlowTest, ConstructorHasOverloadCompletions) +{ + auto myCompleter = setupCompleter(completionsOrder); + const ClangBackEnd::CodeCompletions completions = myCompleter.complete(8, 1); + + int constructorsCount = Utils::count(completions, [](const CodeCompletion &codeCompletion) { + return codeCompletion.text == "Constructor" && codeCompletion.completionKind == CodeCompletion::ConstructorCompletionKind; + }); + + ASSERT_THAT(constructorsCount, 2); +} + ClangBackEnd::CodeCompleter CodeCompleter::setupCompleter( const ClangBackEnd::FileContainer &fileContainer) { diff --git a/tests/unit/unittest/codecompletionsextractor-test.cpp b/tests/unit/unittest/codecompletionsextractor-test.cpp index 3f4ca8f0df3..b7c44f2cca0 100644 --- a/tests/unit/unittest/codecompletionsextractor-test.cpp +++ b/tests/unit/unittest/codecompletionsextractor-test.cpp @@ -794,6 +794,18 @@ TEST_F(CodeCompletionsExtractorSlowTest, OverloadCandidate) }))); } +TEST_F(CodeCompletionsExtractorSlowTest, ExtractAll) +{ + ClangCodeCompleteResults completeResults(getResults(constructorDocument, 25)); + ::CodeCompletionsExtractor extractor( + constructorDocument.translationUnit().cxTranslationUnit(), + completeResults.data()); + + auto codeCompletions = extractor.extractAll(false); + + ASSERT_THAT(codeCompletions.empty(), false); +} + ClangCodeCompleteResults CodeCompletionsExtractor::getResults(const Document &document, uint line, uint column, diff --git a/tests/unit/unittest/data/complete_smartpointer.cpp b/tests/unit/unittest/data/complete_smartpointer.cpp index 1a9bbaf9788..a6e7d73a58a 100644 --- a/tests/unit/unittest/data/complete_smartpointer.cpp +++ b/tests/unit/unittest/data/complete_smartpointer.cpp @@ -27,7 +27,11 @@ template class unique_ptr {}; template -class shared_ptr {}; +class shared_ptr { +public: + void reset(); + Type *operator->(); +}; template unique_ptr make_unique(Args&&... args); @@ -55,4 +59,5 @@ void f2() std::unique_ptr bar = std::make_unique(); std::shared_ptr bar2 = std::make_shared(); QSharedPointer bar3 = QSharedPointer::create(); + bar2-> } diff --git a/tests/unit/unittest/data/completions_order.cpp b/tests/unit/unittest/data/completions_order.cpp new file mode 100644 index 00000000000..6ede7573d85 --- /dev/null +++ b/tests/unit/unittest/data/completions_order.cpp @@ -0,0 +1,9 @@ +class Constructor { +public: + Constructor() = default; + Constructor(int) {} +}; + +void testConstructor() { + +}