diff --git a/plugins/clang/codecompletion/context.cpp b/plugins/clang/codecompletion/context.cpp --- a/plugins/clang/codecompletion/context.cpp +++ b/plugins/clang/codecompletion/context.cpp @@ -1149,6 +1149,19 @@ auto found = findDeclaration(qid, ctx, m_position, isOverloadCandidate ? overloadsHandled : handled); + if (found && found->type() == nullptr && parent.isEmpty() && !resultType.isEmpty()) { + // workaround: for multiple nameless structs with the same member. + // Check the type of the member to have at least a higher probability. + auto typeCheckedDeclaration = found; + while (typeCheckedDeclaration != nullptr && typeCheckedDeclaration->abstractType() != nullptr) { + if (typeCheckedDeclaration->abstractType()->toString() == resultType) { + found = typeCheckedDeclaration; + break; + } + typeCheckedDeclaration = findDeclaration(qid, ctx, m_position, isOverloadCandidate ? overloadsHandled : handled); + } + } + CompletionTreeItemPointer item; if (found) { // TODO: Bug in Clang: protected members from base classes not accessible in derived classes. diff --git a/plugins/clang/tests/test_codecompletion.h b/plugins/clang/tests/test_codecompletion.h --- a/plugins/clang/tests/test_codecompletion.h +++ b/plugins/clang/tests/test_codecompletion.h @@ -35,6 +35,8 @@ void testClangCodeCompletion(); void testClangCodeCompletion_data(); + void testClangCodeCompletionType(); + void testClangCodeCompletionType_data(); void testVirtualOverride(); void testVirtualOverride_data(); void testOverrideExecute(); diff --git a/plugins/clang/tests/test_codecompletion.cpp b/plugins/clang/tests/test_codecompletion.cpp --- a/plugins/clang/tests/test_codecompletion.cpp +++ b/plugins/clang/tests/test_codecompletion.cpp @@ -188,9 +188,10 @@ template void executeCompletionTest(const QString& code, const CompletionItems& expectedCompletionItems, const ClangCodeCompletionContext::ContextFilters& filters = NoMacroOrBuiltin, - CustomTestFunction customTestFunction = {}) + CustomTestFunction customTestFunction = {}, + QString fileExtension = QStringLiteral("cpp")) { - TestFile file(code, QStringLiteral("cpp")); + TestFile file(code, fileExtension); QVERIFY(file.parseAndWait(TopDUContext::AllDeclarationsContextsUsesAndAST)); executeCompletionTest(file.topContext(), expectedCompletionItems, filters, customTestFunction); } @@ -504,6 +505,46 @@ << CompletionItems{{3, 17}, { "Head", "Tail", "my_class" }}; } + +void TestCodeCompletion::testClangCodeCompletionType() +{ + QFETCH(QString, fileExtension); + QFETCH(QString, code); + QFETCH(CompletionItems, expectedItems); + QFETCH(QString, expedtedItem); + QFETCH(QString, expectedType); + + auto executeItem = [=] (const ClangCodeCompletionItemTester& tester) { + auto item = tester.findItem(expedtedItem); + QVERIFY(item); + auto declaration = item->declaration(); + QVERIFY(declaration); + QCOMPARE(declaration->abstractType()->toString(), expectedType); + }; + + executeCompletionTest(code, expectedItems, NoMacroOrBuiltin, executeItem, fileExtension); +} + +void TestCodeCompletion::testClangCodeCompletionType_data() +{ + QTest::addColumn("fileExtension"); + QTest::addColumn("code"); + QTest::addColumn("expectedItems"); + QTest::addColumn("expedtedItem"); + QTest::addColumn("expectedType"); + + QTest::newRow("bug409041") + << "c" + << "typedef struct { int bitmask[1]; } bitmask_a;\n" + "typedef struct { int bitmask[6]; } bitmask_c;\n" + "typedef union { bitmask_c bitmask; } bitmask_union;\n" + "int main() { bitmask_union u;\n" + "u. \n " + << CompletionItems{{4, 2}, { "bitmask" }} + << "bitmask" + << "bitmask_c"; +} + void TestCodeCompletion::testReplaceMemberAccess() { QFETCH(QString, code);