diff --git a/src/libs/cplusplus/LookupContext.cpp b/src/libs/cplusplus/LookupContext.cpp index 6f05f8ea74c..06ecaaf9c6d 100644 --- a/src/libs/cplusplus/LookupContext.cpp +++ b/src/libs/cplusplus/LookupContext.cpp @@ -88,10 +88,10 @@ static bool isNestedInstantiationEnclosingTemplate( ClassOrNamespace *nestedClassOrNamespaceInstantiation, ClassOrNamespace *enclosingTemplateClassInstantiation) { - QList processed; + QSet 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 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 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 processed; + while (!origin->_symbols.isEmpty() && origin->_symbols[0]->isBlock()) { + if (processed.contains(origin)) + break; + processed.insert(origin); origin = origin->parent(); + } instantiation->_instantiationOrigin = origin; diff --git a/src/plugins/cpptools/cppcompletionassist.cpp b/src/plugins/cpptools/cppcompletionassist.cpp index 1e87bbebf8d..f8070985298 100644 --- a/src/plugins/cpptools/cppcompletionassist.cpp +++ b/src/plugins/cpptools/cppcompletionassist.cpp @@ -1513,7 +1513,12 @@ bool InternalCppCompletionAssistProcessor::globalCompletion(Scope *currentScope) } } + QSet processed; for (; currentBinding; currentBinding = currentBinding->parent()) { + if (processed.contains(currentBinding)) + break; + processed.insert(currentBinding); + foreach (ClassOrNamespace* u, currentBinding->usings()) usingBindings.append(u); diff --git a/tests/auto/cplusplus/checksymbols/tst_checksymbols.cpp b/tests/auto/cplusplus/checksymbols/tst_checksymbols.cpp index cf26114d9a1..ccabb8c61fa 100644 --- a/tests/auto/cplusplus/checksymbols/tst_checksymbols.cpp +++ b/tests/auto/cplusplus/checksymbols/tst_checksymbols.cpp @@ -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 struct TNode;\n" + "template struct TMetaNode;\n" + "\n" + "template \n" + "struct TTraits {\n" + " using TX = X;\n" + " using TNodeType = TNode;\n" + "};\n" + "\n" + "template \n" + "struct TMetaNode {\n" + " using TTraitsType = TTraits;\n" + "};\n" + "\n" + "template \n" + "void nonmember() {\n" + " using TMetaNodeType = TMetaNode;\n" + "}\n" + "\n" + "template \n" + "struct TNode {\n" + " using TTraitsType = TTraits;\n" + " void member();\n" + "};\n" + "\n" + "template \n" + "void TNode::member() {}\n" + ; + + BaseTestCase tc(source); +} + void tst_CheckSymbols::test_checksymbols_infiniteLoop_data() { QTest::addColumn("source1");