forked from qt-creator/qt-creator
Fix crashes when cyclic inheritance
Task-number: QTCREATORBUG-7933 Change-Id: I98469a092ff3ff0acc69800e9aade4ebb268332a Reviewed-by: Erik Verbruggen <erik.verbruggen@digia.com>
This commit is contained in:
committed by
Erik Verbruggen
parent
8dc234c171
commit
fbb756cdcc
@@ -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();
|
||||
|
Reference in New Issue
Block a user