Commit af76c02d authored by Sergey Kalinichev's avatar Sergey Kalinichev

Add protected members into completions

This should work around the issue with protected members from base
classes marked as not accessible in derived classes.

See also: https://llvm.org/bugs/show_bug.cgi?id=24329

REVIEW: 124506
parent 7c3eff7f
......@@ -25,6 +25,7 @@
#include <language/duchain/ducontext.h>
#include <language/duchain/topducontext.h>
#include <language/duchain/declaration.h>
#include <language/duchain/classmemberdeclaration.h>
#include <language/duchain/duchainutils.h>
#include <language/duchain/types/functiontype.h>
#include <language/duchain/types/typealiastype.h>
......@@ -508,6 +509,20 @@ Declaration* findDeclaration(const QualifiedIdentifier& qid, const DUContextPoin
return nullptr;
}
/// If any parent of this context is a class, the closest class declaration is returned, nullptr otherwise
Declaration* classDeclarationForContext(const DUContextPointer& context)
{
auto parent = context;
while (parent) {
if (parent->type() == DUContext::Class) {
break;
}
parent = parent->parentContext();
}
return parent ? parent->owner() : nullptr;
}
}
ClangCodeCompletionContext::ClangCodeCompletionContext(const DUContextPointer& context,
......@@ -600,7 +615,7 @@ QList<CompletionTreeItemPointer> ClangCodeCompletionContext::completionItems(boo
auto result = m_results->Results[i];
const auto availability = clang_getCompletionAvailability(result.CompletionString);
if (availability == CXAvailability_NotAvailable || availability == CXAvailability_NotAccessible) {
if (availability == CXAvailability_NotAvailable) {
continue;
}
......@@ -619,6 +634,10 @@ QList<CompletionTreeItemPointer> ClangCodeCompletionContext::completionItems(boo
continue;
}
if (availability == CXAvailability_NotAccessible && (!isDeclaration || !classDeclarationForContext(ctx))) {
continue;
}
const uint chunks = clang_getNumCompletionChunks(result.CompletionString);
// the string that would be needed to type, usually the identifier of something. Also we use it as name for code completion declaration items.
......@@ -717,6 +736,26 @@ QList<CompletionTreeItemPointer> ClangCodeCompletionContext::completionItems(boo
CompletionTreeItemPointer item;
if (found) {
// TODO: Bug in Clang: protected members from base classes not accessible in derived classes.
if (availability == CXAvailability_NotAccessible) {
if (auto cl = dynamic_cast<ClassMemberDeclaration*>(found)) {
if (cl->accessPolicy() != Declaration::Protected) {
continue;
}
auto declarationClassContext = classDeclarationForContext(DUContextPointer(found->context()));
auto currentClassContext = classDeclarationForContext(ctx);
uint steps = 10;
auto inheriters = DUChainUtils::getInheriters(declarationClassContext, steps);
if(!inheriters.contains(currentClassContext)){
continue;
}
} else {
continue;
}
}
auto declarationItem = new DeclarationItem(found, display, resultType, replacement);
const unsigned int completionPriority = adjustPriorityForDeclaration(found, clang_getCompletionPriority(result.CompletionString));
......
......@@ -177,6 +177,7 @@ void executeCompletionPriorityTest(const QString& code, const CompletionPriority
for(const auto& declaration : expectedCompletionItems.completions){
const auto declarationItem = tester.findItem(declaration.name);
QEXPECT_FAIL("protected-access2", declaration.failMessage.toUtf8().constData(), Abort);
QVERIFY(declarationItem);
QVERIFY(declarationItem->declaration());
......@@ -713,4 +714,15 @@ void TestCodeCompletion::testCompletionPriority_data()
<< "template <typename T> class Class{}; template <typename T> class Class2{};"
"int main(){ Class<int> a; Class2<int> b =\n }"
<< CompletionPriorityItems{{1,0}, {{"b", 9, 0}, {"a", 0, 21}}};
QTest::newRow("protected-access")
<< "class Base { protected: int m_protected; };"
"class Derived: public Base {public: void g(){\n }};"
<< CompletionPriorityItems{{1,0}, {{"m_protected", 0, 37}}};
QTest::newRow("protected-access2")
<< "class Base { protected: int m_protected; };"
"class Derived: public Base {public: void f();};"
"void Derived::f(){\n }"
<< CompletionPriorityItems{{1,0}, {{"m_protected", 0, 37, QStringLiteral("Out of line methods have wrong parent context attached (Global instead of Class)")}}};
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment