forked from qt-creator/qt-creator
C++: Guard against parent binding loop
Task-number: QTCREATORBUG-16146 Change-Id: Ib2a790954517859acd7ca5f16c7d889d28208fb0 Reviewed-by: Erik Verbruggen <erik.verbruggen@qt.io>
This commit is contained in:
committed by
Erik Verbruggen
parent
c4f9c6f265
commit
a717e980e7
@@ -88,10 +88,10 @@ static bool isNestedInstantiationEnclosingTemplate(
|
|||||||
ClassOrNamespace *nestedClassOrNamespaceInstantiation,
|
ClassOrNamespace *nestedClassOrNamespaceInstantiation,
|
||||||
ClassOrNamespace *enclosingTemplateClassInstantiation)
|
ClassOrNamespace *enclosingTemplateClassInstantiation)
|
||||||
{
|
{
|
||||||
QList<ClassOrNamespace *> processed;
|
QSet<ClassOrNamespace *> processed;
|
||||||
while (enclosingTemplateClassInstantiation
|
while (enclosingTemplateClassInstantiation
|
||||||
&& !processed.contains(enclosingTemplateClassInstantiation)) {
|
&& !processed.contains(enclosingTemplateClassInstantiation)) {
|
||||||
processed.append(enclosingTemplateClassInstantiation);
|
processed.insert(enclosingTemplateClassInstantiation);
|
||||||
if (enclosingTemplateClassInstantiation == nestedClassOrNamespaceInstantiation)
|
if (enclosingTemplateClassInstantiation == nestedClassOrNamespaceInstantiation)
|
||||||
return false;
|
return false;
|
||||||
enclosingTemplateClassInstantiation = enclosingTemplateClassInstantiation->parent();
|
enclosingTemplateClassInstantiation = enclosingTemplateClassInstantiation->parent();
|
||||||
@@ -454,8 +454,13 @@ QList<LookupItem> LookupContext::lookup(const Name *name, Scope *scope) const
|
|||||||
candidates = binding->find(name);
|
candidates = binding->find(name);
|
||||||
|
|
||||||
// try find this name in parent class
|
// 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);
|
candidates = binding->find(name);
|
||||||
|
}
|
||||||
|
|
||||||
if (! candidates.isEmpty())
|
if (! candidates.isEmpty())
|
||||||
return candidates;
|
return candidates;
|
||||||
@@ -1143,8 +1148,13 @@ ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, ClassOrNamespac
|
|||||||
instantiation->_name = templId;
|
instantiation->_name = templId;
|
||||||
instantiation->_templateId = 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();
|
origin = origin->parent();
|
||||||
|
}
|
||||||
|
|
||||||
instantiation->_instantiationOrigin = origin;
|
instantiation->_instantiationOrigin = origin;
|
||||||
|
|
||||||
|
|||||||
@@ -1513,7 +1513,12 @@ bool InternalCppCompletionAssistProcessor::globalCompletion(Scope *currentScope)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QSet<ClassOrNamespace *> processed;
|
||||||
for (; currentBinding; currentBinding = currentBinding->parent()) {
|
for (; currentBinding; currentBinding = currentBinding->parent()) {
|
||||||
|
if (processed.contains(currentBinding))
|
||||||
|
break;
|
||||||
|
processed.insert(currentBinding);
|
||||||
|
|
||||||
foreach (ClassOrNamespace* u, currentBinding->usings())
|
foreach (ClassOrNamespace* u, currentBinding->usings())
|
||||||
usingBindings.append(u);
|
usingBindings.append(u);
|
||||||
|
|
||||||
|
|||||||
@@ -222,6 +222,7 @@ private slots:
|
|||||||
void test_checkForValidSymbolFileId();
|
void test_checkForValidSymbolFileId();
|
||||||
|
|
||||||
void test_parentOfBlock();
|
void test_parentOfBlock();
|
||||||
|
void test_infiniteLoop();
|
||||||
|
|
||||||
void findField();
|
void findField();
|
||||||
void findField_data();
|
void findField_data();
|
||||||
@@ -1203,6 +1204,41 @@ void tst_CheckSymbols::test_parentOfBlock()
|
|||||||
BaseTestCase tc(source);
|
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()
|
void tst_CheckSymbols::test_checksymbols_infiniteLoop_data()
|
||||||
{
|
{
|
||||||
QTest::addColumn<QByteArray>("source1");
|
QTest::addColumn<QByteArray>("source1");
|
||||||
|
|||||||
Reference in New Issue
Block a user