Commit fbb756cd authored by Przemyslaw Gorszkowski's avatar Przemyslaw Gorszkowski Committed by Erik Verbruggen

Fix crashes when cyclic inheritance

Task-number: QTCREATORBUG-7933

Change-Id: I98469a092ff3ff0acc69800e9aade4ebb268332a
Reviewed-by: default avatarErik Verbruggen <erik.verbruggen@digia.com>
parent 8dc234c1
......@@ -708,11 +708,22 @@ ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, ClassOrNamespac
if (!referenceClass)
return reference;
const TemplateNameId *templId = name->asTemplateNameId();
if (_alreadyConsideredClasses.contains(referenceClass) ||
(templId &&
_alreadyConsideredTemplates.contains(templId))) {
return reference;
}
if (!name->isTemplateNameId())
_alreadyConsideredClasses.insert(referenceClass);
QSet<ClassOrNamespace *> knownUsings = reference->usings().toSet();
// If we are dealling with a template type, more work is required, since we need to
// construct all instantiation data.
if (const TemplateNameId *templId = name->asTemplateNameId()) {
if (templId) {
_alreadyConsideredTemplates.insert(templId);
ClassOrNamespace *instantiation = _factory->allocClassOrNamespace(reference);
instantiation->_templateId = templId;
instantiation->_instantiationOrigin = origin;
......@@ -786,6 +797,7 @@ ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, ClassOrNamespac
}
}
_alreadyConsideredTemplates.clear(templId);
return instantiation;
}
......@@ -828,6 +840,7 @@ ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, ClassOrNamespac
}
}
_alreadyConsideredClasses.clear(referenceClass);
return reference;
}
......
......@@ -45,6 +45,33 @@
namespace CPlusPlus {
class CreateBindings;
class Class;
template<typename T>
class AlreadyConsideredClassContainer
{
public:
AlreadyConsideredClassContainer() : _class(0) {}
void insert(const T *item)
{
if (_container.isEmpty())
_class = item;
_container.insert(item);
}
bool contains(const T *item)
{
return _container.contains(item);
}
void clear(const T *item)
{
if (_class != item)
_container.clear();
}
private:
QSet<const T *> _container;
const T * _class;
};
class CPLUSPLUS_EXPORT ClassOrNamespace
{
......@@ -112,6 +139,9 @@ private:
const TemplateNameId *_templateId;
ClassOrNamespace *_instantiationOrigin;
AlreadyConsideredClassContainer<Class> _alreadyConsideredClasses;
AlreadyConsideredClassContainer<TemplateNameId> _alreadyConsideredTemplates;
friend class CreateBindings;
};
......
......@@ -672,3 +672,123 @@ void CppToolsPlugin::test_completion_base_class_has_name_the_same_as_derived_dat
completions.clear();
}
void CppToolsPlugin::test_completion_cyclic_inheritance()
{
test_completion();
}
void CppToolsPlugin::test_completion_cyclic_inheritance_data()
{
QTest::addColumn<QByteArray>("code");
QTest::addColumn<QStringList>("expectedCompletions");
QByteArray code;
QStringList completions;
code = "\n"
"struct B;\n"
"struct A : B { int _a; };\n"
"struct B : A { int _b; };\n"
"\n"
"A c;\n"
"@\n"
;
completions.append("A");
completions.append("_a");
completions.append("B");
completions.append("_b");
QTest::newRow("case: direct cyclic inheritance") << code << completions;
completions.clear();
code = "\n"
"struct C;\n"
"struct A : C { int _a; };\n"
"struct B : A { int _b; };\n"
"struct C : B { int _c; };\n"
"\n"
"A c;\n"
"@\n"
;
completions.append("A");
completions.append("_a");
completions.append("B");
completions.append("_b");
completions.append("C");
completions.append("_c");
QTest::newRow("case: indirect cyclic inheritance") << code << completions;
completions.clear();
code = "\n"
"struct B;\n"
"struct A : B { int _a; };\n"
"struct C { int _c; };\n"
"struct B : C, A { int _b; };\n"
"\n"
"A c;\n"
"@\n"
;
completions.append("A");
completions.append("_a");
completions.append("B");
completions.append("_b");
completions.append("C");
completions.append("_c");
QTest::newRow("case: indirect cyclic inheritance") << code << completions;
completions.clear();
code = "\n"
"template< typename T > struct C;\n"
"template< typename T, typename S > struct D : C< S >\n"
"{\n"
" T _d_t;\n"
" S _d_s;\n"
"};\n"
"template< typename T > struct C : D< T, int >\n"
"{\n"
" T _c_t;\n"
"};\n"
"\n"
"D<int, float> c;\n"
"@\n"
;
completions.append("D");
completions.append("_d_t");
completions.append("_d_s");
completions.append("C");
completions.append("_c_t");
QTest::newRow("case: direct cyclic inheritance with templates")
<< code << completions;
completions.clear();
code = "\n"
"template< typename T > struct C;\n"
"template< typename T, typename S > struct D : C< S >\n"
"{\n"
" T _d_t;\n"
" S _d_s;\n"
"};\n"
"template< typename T > struct B : D< T, int >\n"
"{\n"
" T _b_t;\n"
"};\n"
"template< typename T > struct C : B<T>\n"
"{\n"
" T _c_t;\n"
"};\n"
"\n"
"D<int, float> c;\n"
"@\n"
;
completions.append("D");
completions.append("_d_t");
completions.append("_d_s");
completions.append("C");
completions.append("_c_t");
completions.append("B");
completions.append("_b_t");
QTest::newRow("case: indirect cyclic inheritance with templates")
<< code << completions;
}
......@@ -100,6 +100,8 @@ private slots:
void test_completion_use_global_identifier_as_base_class_data();
void test_completion_base_class_has_name_the_same_as_derived();
void test_completion_base_class_has_name_the_same_as_derived_data();
void test_completion_cyclic_inheritance();
void test_completion_cyclic_inheritance_data();
private:
void test_completion();
......
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