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)
|
if (!referenceClass)
|
||||||
return reference;
|
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();
|
QSet<ClassOrNamespace *> knownUsings = reference->usings().toSet();
|
||||||
|
|
||||||
// If we are dealling with a template type, more work is required, since we need to
|
// If we are dealling with a template type, more work is required, since we need to
|
||||||
// construct all instantiation data.
|
// construct all instantiation data.
|
||||||
if (const TemplateNameId *templId = name->asTemplateNameId()) {
|
if (templId) {
|
||||||
|
_alreadyConsideredTemplates.insert(templId);
|
||||||
ClassOrNamespace *instantiation = _factory->allocClassOrNamespace(reference);
|
ClassOrNamespace *instantiation = _factory->allocClassOrNamespace(reference);
|
||||||
instantiation->_templateId = templId;
|
instantiation->_templateId = templId;
|
||||||
instantiation->_instantiationOrigin = origin;
|
instantiation->_instantiationOrigin = origin;
|
||||||
@@ -786,6 +797,7 @@ ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, ClassOrNamespac
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_alreadyConsideredTemplates.clear(templId);
|
||||||
return instantiation;
|
return instantiation;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -828,6 +840,7 @@ ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, ClassOrNamespac
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_alreadyConsideredClasses.clear(referenceClass);
|
||||||
return reference;
|
return reference;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -45,6 +45,33 @@
|
|||||||
namespace CPlusPlus {
|
namespace CPlusPlus {
|
||||||
|
|
||||||
class CreateBindings;
|
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
|
class CPLUSPLUS_EXPORT ClassOrNamespace
|
||||||
{
|
{
|
||||||
@@ -112,6 +139,9 @@ private:
|
|||||||
const TemplateNameId *_templateId;
|
const TemplateNameId *_templateId;
|
||||||
ClassOrNamespace *_instantiationOrigin;
|
ClassOrNamespace *_instantiationOrigin;
|
||||||
|
|
||||||
|
AlreadyConsideredClassContainer<Class> _alreadyConsideredClasses;
|
||||||
|
AlreadyConsideredClassContainer<TemplateNameId> _alreadyConsideredTemplates;
|
||||||
|
|
||||||
friend class CreateBindings;
|
friend class CreateBindings;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -672,3 +672,123 @@ void CppToolsPlugin::test_completion_base_class_has_name_the_same_as_derived_dat
|
|||||||
completions.clear();
|
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_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();
|
||||||
void test_completion_base_class_has_name_the_same_as_derived_data();
|
void test_completion_base_class_has_name_the_same_as_derived_data();
|
||||||
|
void test_completion_cyclic_inheritance();
|
||||||
|
void test_completion_cyclic_inheritance_data();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void test_completion();
|
void test_completion();
|
||||||
|
Reference in New Issue
Block a user