Commit a717e980 authored by Nikolai Kosjar's avatar Nikolai Kosjar Committed by Erik Verbruggen

C++: Guard against parent binding loop

Task-number: QTCREATORBUG-16146
Change-Id: Ib2a790954517859acd7ca5f16c7d889d28208fb0
Reviewed-by: Erik Verbruggen's avatarErik Verbruggen <erik.verbruggen@qt.io>
parent c4f9c6f2
......@@ -88,10 +88,10 @@ static bool isNestedInstantiationEnclosingTemplate(
ClassOrNamespace *nestedClassOrNamespaceInstantiation,
ClassOrNamespace *enclosingTemplateClassInstantiation)
{
QList<ClassOrNamespace *> processed;
QSet<ClassOrNamespace *> processed;
while (enclosingTemplateClassInstantiation
&& !processed.contains(enclosingTemplateClassInstantiation)) {
processed.append(enclosingTemplateClassInstantiation);
processed.insert(enclosingTemplateClassInstantiation);
if (enclosingTemplateClassInstantiation == nestedClassOrNamespaceInstantiation)
return false;
enclosingTemplateClassInstantiation = enclosingTemplateClassInstantiation->parent();
......@@ -454,8 +454,13 @@ QList<LookupItem> LookupContext::lookup(const Name *name, Scope *scope) const
candidates = binding->find(name);
// try find this name in parent class
while (candidates.isEmpty() && (binding = binding->parent()))
QSet<ClassOrNamespace *> processed;
while (candidates.isEmpty() && (binding = binding->parent())) {
if (processed.contains(binding))
break;
processed.insert(binding);
candidates = binding->find(name);
}
if (! candidates.isEmpty())
return candidates;
......@@ -1143,8 +1148,13 @@ ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, ClassOrNamespac
instantiation->_name = templId;
instantiation->_templateId = templId;
while (!origin->_symbols.isEmpty() && origin->_symbols[0]->isBlock())
QSet<ClassOrNamespace *> processed;
while (!origin->_symbols.isEmpty() && origin->_symbols[0]->isBlock()) {
if (processed.contains(origin))
break;
processed.insert(origin);
origin = origin->parent();
}
instantiation->_instantiationOrigin = origin;
......
......@@ -1513,7 +1513,12 @@ bool InternalCppCompletionAssistProcessor::globalCompletion(Scope *currentScope)
}
}
QSet<ClassOrNamespace *> processed;
for (; currentBinding; currentBinding = currentBinding->parent()) {
if (processed.contains(currentBinding))
break;
processed.insert(currentBinding);
foreach (ClassOrNamespace* u, currentBinding->usings())
usingBindings.append(u);
......
......@@ -222,6 +222,7 @@ private slots:
void test_checkForValidSymbolFileId();
void test_parentOfBlock();
void test_infiniteLoop();
void findField();
void findField_data();
......@@ -1203,6 +1204,41 @@ void tst_CheckSymbols::test_parentOfBlock()
BaseTestCase tc(source);
}
void tst_CheckSymbols::test_infiniteLoop()
{
const QByteArray source =
"template <class> struct TNode;\n"
"template <class> struct TMetaNode;\n"
"\n"
"template <class X>\n"
"struct TTraits {\n"
" using TX = X;\n"
" using TNodeType = TNode<TX>;\n"
"};\n"
"\n"
"template <class X>\n"
"struct TMetaNode {\n"
" using TTraitsType = TTraits<X>;\n"
"};\n"
"\n"
"template <class X>\n"
"void nonmember() {\n"
" using TMetaNodeType = TMetaNode<X>;\n"
"}\n"
"\n"
"template <class X>\n"
"struct TNode {\n"
" using TTraitsType = TTraits<X>;\n"
" void member();\n"
"};\n"
"\n"
"template <class X>\n"
"void TNode<X>::member() {}\n"
;
BaseTestCase tc(source);
}
void tst_CheckSymbols::test_checksymbols_infiniteLoop_data()
{
QTest::addColumn<QByteArray>("source1");
......
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