From fbb756cdcc3976a3afb8ffec5477b19ec77914c9 Mon Sep 17 00:00:00 2001 From: Przemyslaw Gorszkowski <pgorszkowski@gmail.com> Date: Sun, 30 Sep 2012 23:19:53 +0200 Subject: [PATCH] Fix crashes when cyclic inheritance Task-number: QTCREATORBUG-7933 Change-Id: I98469a092ff3ff0acc69800e9aade4ebb268332a Reviewed-by: Erik Verbruggen <erik.verbruggen@digia.com> --- src/libs/cplusplus/LookupContext.cpp | 15 ++- src/libs/cplusplus/LookupContext.h | 30 +++++ src/plugins/cpptools/cppcompletion_test.cpp | 120 ++++++++++++++++++++ src/plugins/cpptools/cpptoolsplugin.h | 2 + 4 files changed, 166 insertions(+), 1 deletion(-) diff --git a/src/libs/cplusplus/LookupContext.cpp b/src/libs/cplusplus/LookupContext.cpp index e474287d199..3e675644075 100644 --- a/src/libs/cplusplus/LookupContext.cpp +++ b/src/libs/cplusplus/LookupContext.cpp @@ -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; } diff --git a/src/libs/cplusplus/LookupContext.h b/src/libs/cplusplus/LookupContext.h index fef317fd614..6db8b1187de 100644 --- a/src/libs/cplusplus/LookupContext.h +++ b/src/libs/cplusplus/LookupContext.h @@ -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; }; diff --git a/src/plugins/cpptools/cppcompletion_test.cpp b/src/plugins/cpptools/cppcompletion_test.cpp index 08e14bd67a6..8f0b5ecbe3b 100644 --- a/src/plugins/cpptools/cppcompletion_test.cpp +++ b/src/plugins/cpptools/cppcompletion_test.cpp @@ -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; + +} diff --git a/src/plugins/cpptools/cpptoolsplugin.h b/src/plugins/cpptools/cpptoolsplugin.h index 554a1877832..d84319db03b 100644 --- a/src/plugins/cpptools/cpptoolsplugin.h +++ b/src/plugins/cpptools/cpptoolsplugin.h @@ -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(); -- GitLab