forked from qt-creator/qt-creator
C++: fix support for nested anonymous classes
A member of nested anonymous class should be visible as a member of enclosing class(if there is no declaration of this nested anonymous class). Fix: * marking * find usage * follow symbol * completion Task-number: QTCREATORBUG-10876 Task-number: QTCREATORBUG-11170 Change-Id: If5b4d198e9075f2a8aa899ae59190f2c05f7b1ff Reviewed-by: Orgad Shaneh <orgads@gmail.com> Reviewed-by: Przemyslaw Gorszkowski <pgorszkowski@gmail.com> Reviewed-by: Erik Verbruggen <erik.verbruggen@digia.com>
This commit is contained in:
committed by
Erik Verbruggen
parent
b96bb6172e
commit
376f77952e
@@ -680,6 +680,15 @@ void ClassOrNamespace::lookup_helper(const Name *name, ClassOrNamespace *binding
|
||||
|
||||
foreach (ClassOrNamespace *u, binding->usings())
|
||||
lookup_helper(name, u, result, processed, binding->_templateId);
|
||||
|
||||
Anonymouses::const_iterator cit = binding->_anonymouses.begin();
|
||||
Anonymouses::const_iterator citEnd = binding->_anonymouses.end();
|
||||
for (; cit != citEnd; ++cit) {
|
||||
const AnonymousNameId *anonymousNameId = cit.key();
|
||||
ClassOrNamespace *a = cit.value();
|
||||
if (!binding->_declaredAnonymouses.contains(anonymousNameId))
|
||||
lookup_helper(name, a, result, processed, binding->_templateId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1578,8 +1587,12 @@ bool CreateBindings::visit(Declaration *decl)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (Class *clazz = decl->type()->asClassType()) {
|
||||
if (const Name *name = clazz->name()) {
|
||||
if (const AnonymousNameId *anonymousNameId = name->asAnonymousNameId())
|
||||
_currentClassOrNamespace->_declaredAnonymouses.insert(anonymousNameId);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -93,6 +93,7 @@ public:
|
||||
private:
|
||||
typedef std::map<const Name *, ClassOrNamespace *, Name::Compare> Table;
|
||||
typedef std::map<const TemplateNameId *, ClassOrNamespace *, TemplateNameId::Compare> TemplateNameIdTable;
|
||||
typedef QHash<const AnonymousNameId *, ClassOrNamespace *> Anonymouses;
|
||||
|
||||
/// \internal
|
||||
void flush();
|
||||
@@ -138,7 +139,8 @@ private:
|
||||
QSharedPointer<Control> _control;
|
||||
TemplateNameIdTable _specializations;
|
||||
QMap<const TemplateNameId *, ClassOrNamespace *> _instantiations;
|
||||
QHash<const AnonymousNameId *, ClassOrNamespace *> _anonymouses;
|
||||
Anonymouses _anonymouses;
|
||||
QSet<const AnonymousNameId *> _declaredAnonymouses;
|
||||
|
||||
QHash<Internal::FullyQualifiedName, Symbol *> *_scopeLookupCache;
|
||||
|
||||
|
||||
@@ -1425,7 +1425,9 @@ void CppToolsPlugin::test_completion_data()
|
||||
" @\n"
|
||||
"}\n"
|
||||
) << _("s.") << (QStringList()
|
||||
<< QLatin1String("S"));
|
||||
<< QLatin1String("S")
|
||||
<< QLatin1String("i")
|
||||
<< QLatin1String("c"));
|
||||
|
||||
QTest::newRow("instantiate_template_function") << _(
|
||||
"template <typename T>\n"
|
||||
@@ -1439,6 +1441,65 @@ void CppToolsPlugin::test_completion_data()
|
||||
<< QLatin1String("A")
|
||||
<< QLatin1String("a"));
|
||||
|
||||
QTest::newRow("nested_anonymous_class_QTCREATORBUG10876_1") << _(
|
||||
"struct EnclosingStruct\n"
|
||||
"{\n"
|
||||
" int memberOfEnclosingStruct;\n"
|
||||
" struct\n"
|
||||
" {\n"
|
||||
" int memberNestedAnonymousClass;\n"
|
||||
" };\n"
|
||||
" void fun()\n"
|
||||
" {\n"
|
||||
" @\n"
|
||||
" }\n"
|
||||
"};\n"
|
||||
) << _("member") << (QStringList()
|
||||
<< QLatin1String("memberNestedAnonymousClass")
|
||||
<< QLatin1String("memberOfEnclosingStruct"));
|
||||
|
||||
QTest::newRow("nested_anonymous_class_QTCREATORBUG10876_2") << _(
|
||||
"struct EnclosingStruct\n"
|
||||
"{\n"
|
||||
" int memberOfEnclosingStruct;\n"
|
||||
" struct\n"
|
||||
" {\n"
|
||||
" int memberOfNestedAnonymousClass;\n"
|
||||
" struct\n"
|
||||
" {\n"
|
||||
" int memberOfNestedOfNestedAnonymousClass;\n"
|
||||
" };\n"
|
||||
" };\n"
|
||||
" void fun()\n"
|
||||
" {\n"
|
||||
" @\n"
|
||||
" }\n"
|
||||
"};\n"
|
||||
) << _("member") << (QStringList()
|
||||
<< QLatin1String("memberOfNestedAnonymousClass")
|
||||
<< QLatin1String("memberOfNestedOfNestedAnonymousClass")
|
||||
<< QLatin1String("memberOfEnclosingStruct"));
|
||||
|
||||
QTest::newRow("nested_anonymous_class_QTCREATORBUG10876_3") << _(
|
||||
"struct EnclosingStruct\n"
|
||||
"{\n"
|
||||
" int memberOfEnclosingStruct;\n"
|
||||
" struct\n"
|
||||
" {\n"
|
||||
" int memberOfNestedAnonymousClass;\n"
|
||||
" struct\n"
|
||||
" {\n"
|
||||
" int memberOfNestedOfNestedAnonymousClass;\n"
|
||||
" } nestedOfNestedAnonymousClass;\n"
|
||||
" };\n"
|
||||
" void fun()\n"
|
||||
" {\n"
|
||||
" @\n"
|
||||
" }\n"
|
||||
"};\n"
|
||||
) << _("nestedOfNestedAnonymousClass.") << (QStringList()
|
||||
<< QLatin1String("memberOfNestedOfNestedAnonymousClass"));
|
||||
|
||||
QTest::newRow("crash_cloning_template_class_QTCREATORBUG9329") << _(
|
||||
"struct A {};\n"
|
||||
"template <typename T>\n"
|
||||
|
||||
@@ -1554,27 +1554,46 @@ void CppCompletionAssistProcessor::completeClass(CPlusPlus::ClassOrNamespace *b,
|
||||
if (staticLookup)
|
||||
addCompletionItem(scope, InjectedClassNameOrder); // add a completion item for the injected class name.
|
||||
|
||||
for (Scope::iterator it = scope->firstMember(); it != scope->lastMember(); ++it) {
|
||||
Symbol *member = *it;
|
||||
if (member->isFriend()
|
||||
|| member->isQtPropertyDeclaration()
|
||||
|| member->isQtEnum()) {
|
||||
continue;
|
||||
} else if (!staticLookup && (member->isTypedef() ||
|
||||
member->isEnum() ||
|
||||
member->isClass())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (member->isPublic())
|
||||
addCompletionItem(member, PublicClassMemberOrder);
|
||||
else
|
||||
addCompletionItem(member);
|
||||
}
|
||||
addClassMembersToCompletion(scope, staticLookup);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CppCompletionAssistProcessor::addClassMembersToCompletion(Scope *scope, bool staticLookup)
|
||||
{
|
||||
if (!scope)
|
||||
return;
|
||||
|
||||
std::set<Class *> nestedAnonymouses;
|
||||
|
||||
for (Scope::iterator it = scope->firstMember(); it != scope->lastMember(); ++it) {
|
||||
Symbol *member = *it;
|
||||
if (member->isFriend()
|
||||
|| member->isQtPropertyDeclaration()
|
||||
|| member->isQtEnum()) {
|
||||
continue;
|
||||
} else if (!staticLookup && (member->isTypedef() ||
|
||||
member->isEnum() ||
|
||||
member->isClass())) {
|
||||
continue;
|
||||
} else if (member->isClass() && member->name()->isAnonymousNameId()) {
|
||||
nestedAnonymouses.insert(member->asClass());
|
||||
} else if (member->isDeclaration()) {
|
||||
Class *declTypeAsClass = member->asDeclaration()->type()->asClassType();
|
||||
if (declTypeAsClass && declTypeAsClass->name()->isAnonymousNameId())
|
||||
nestedAnonymouses.erase(declTypeAsClass);
|
||||
}
|
||||
|
||||
if (member->isPublic())
|
||||
addCompletionItem(member, PublicClassMemberOrder);
|
||||
else
|
||||
addCompletionItem(member);
|
||||
}
|
||||
std::set<Class *>::const_iterator citEnd = nestedAnonymouses.end();
|
||||
for (std::set<Class *>::const_iterator cit = nestedAnonymouses.begin(); cit != citEnd; ++cit)
|
||||
addClassMembersToCompletion(*cit, staticLookup);
|
||||
}
|
||||
|
||||
bool CppCompletionAssistProcessor::completeQtMethod(const QList<CPlusPlus::LookupItem> &results, bool wantSignals)
|
||||
{
|
||||
if (results.isEmpty())
|
||||
|
||||
@@ -136,6 +136,7 @@ private:
|
||||
bool completeScope(const QList<CPlusPlus::LookupItem> &results);
|
||||
void completeNamespace(CPlusPlus::ClassOrNamespace *binding);
|
||||
void completeClass(CPlusPlus::ClassOrNamespace *b, bool staticLookup = true);
|
||||
void addClassMembersToCompletion(CPlusPlus::Scope *scope, bool staticLookup);
|
||||
bool completeQtMethod(const QList<CPlusPlus::LookupItem> &results, bool wantSignals);
|
||||
bool completeSignal(const QList<CPlusPlus::LookupItem> &results)
|
||||
{ return completeQtMethod(results, true); }
|
||||
|
||||
@@ -1539,7 +1539,9 @@ void tst_CheckSymbols::test_checksymbols_AnonymousClass_insideNamespace()
|
||||
<< Use(13, 11, 3, CppHighlightingSupport::TypeUse)
|
||||
<< Use(15, 27, 4, CppHighlightingSupport::FieldUse)
|
||||
<< Use(16, 10, 4, CppHighlightingSupport::FunctionUse)
|
||||
<< Use(16, 19, 4, CppHighlightingSupport::FieldUse)
|
||||
<< Use(18, 8, 4, CppHighlightingSupport::FunctionUse)
|
||||
<< Use(20, 10, 4, CppHighlightingSupport::FieldUse)
|
||||
;
|
||||
|
||||
TestData::check(source, expectedUses);
|
||||
|
||||
Reference in New Issue
Block a user