forked from qt-creator/qt-creator
C++: Check for cycled parents
In the struct _Wrap_alloc (see test code) the rebind struct has _Wrap_alloc as parent. However, within rebind the typedef of type _Wrap_alloc has rebind as parent. We will refactor that in master by introducing a "parent iterator" class checking for cycles, so the client code looks less noisy. Task-number: QTCREATORBUG-13703 Change-Id: I7b6cf819ea869139d2403e15ba085d8fba19763e Reviewed-by: Cristian Adam <cristian.adam@gmail.com> Reviewed-by: Przemyslaw Gorszkowski <pgorszkowski@gmail.com> Reviewed-by: Eike Ziller <eike.ziller@theqtcompany.com> Reviewed-by: Erik Verbruggen <erik.verbruggen@theqtcompany.com>
This commit is contained in:
committed by
Nikolai Kosjar
parent
309d38c8f0
commit
56dab9e931
@@ -631,10 +631,15 @@ QList<LookupItem> ClassOrNamespace::lookup_helper(const Name *name, bool searchI
|
|||||||
// a qualified name. For instance, a nested class which is forward declared
|
// a qualified name. For instance, a nested class which is forward declared
|
||||||
// in the class but defined outside it - we should capture both.
|
// in the class but defined outside it - we should capture both.
|
||||||
Symbol *match = 0;
|
Symbol *match = 0;
|
||||||
|
QSet<ClassOrNamespace *> processed;
|
||||||
for (ClassOrNamespace *parentBinding = binding->parent();
|
for (ClassOrNamespace *parentBinding = binding->parent();
|
||||||
parentBinding && !match;
|
parentBinding && !match;
|
||||||
parentBinding = parentBinding->parent())
|
parentBinding = parentBinding->parent()) {
|
||||||
|
if (processed.contains(parentBinding))
|
||||||
|
break;
|
||||||
|
processed.insert(parentBinding);
|
||||||
match = parentBinding->lookupInScope(fullName);
|
match = parentBinding->lookupInScope(fullName);
|
||||||
|
}
|
||||||
|
|
||||||
if (match) {
|
if (match) {
|
||||||
LookupItem item;
|
LookupItem item;
|
||||||
@@ -648,8 +653,12 @@ QList<LookupItem> ClassOrNamespace::lookup_helper(const Name *name, bool searchI
|
|||||||
}
|
}
|
||||||
|
|
||||||
QSet<ClassOrNamespace *> processed;
|
QSet<ClassOrNamespace *> processed;
|
||||||
|
QSet<ClassOrNamespace *> processedOwnParents;
|
||||||
ClassOrNamespace *binding = this;
|
ClassOrNamespace *binding = this;
|
||||||
do {
|
do {
|
||||||
|
if (processedOwnParents.contains(binding))
|
||||||
|
break;
|
||||||
|
processedOwnParents.insert(binding);
|
||||||
lookup_helper(name, binding, &result, &processed, /*templateId = */ 0);
|
lookup_helper(name, binding, &result, &processed, /*templateId = */ 0);
|
||||||
binding = binding->_parent;
|
binding = binding->_parent;
|
||||||
} while (searchInEnclosingScope && binding);
|
} while (searchInEnclosingScope && binding);
|
||||||
|
|||||||
@@ -193,6 +193,7 @@ private slots:
|
|||||||
void test_checksymbols_macroUses();
|
void test_checksymbols_macroUses();
|
||||||
void test_checksymbols_macroUses_data();
|
void test_checksymbols_macroUses_data();
|
||||||
|
|
||||||
|
void test_checksymbols_infiniteLoop_data();
|
||||||
void test_checksymbols_infiniteLoop();
|
void test_checksymbols_infiniteLoop();
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1756,36 +1757,12 @@ void tst_CheckSymbols::test_checksymbols_macroUses_data()
|
|||||||
|
|
||||||
void tst_CheckSymbols::test_checksymbols_infiniteLoop()
|
void tst_CheckSymbols::test_checksymbols_infiniteLoop()
|
||||||
{
|
{
|
||||||
const QByteArray source1 =
|
QFETCH(QByteArray, source1);
|
||||||
"#include \"file2.h\"\n"
|
QFETCH(QByteArray, source2);
|
||||||
"\n"
|
|
||||||
"template<class _Elem, class _Traits>\n"
|
|
||||||
"class basic_ios {\n"
|
|
||||||
" typedef basic_ostream<_Elem, _Traits> _Myos;\n"
|
|
||||||
"};\n"
|
|
||||||
"\n"
|
|
||||||
"template<class _Elem, class _Traits>\n"
|
|
||||||
"class basic_ostream {\n"
|
|
||||||
" typedef basic_ostream<_Elem, _Traits> _Myt;\n"
|
|
||||||
" typedef ostreambuf_iterator<_Elem, _Traits> _Iter;\n"
|
|
||||||
"};\n"
|
|
||||||
;
|
|
||||||
const QString filePath1 = QDir::tempPath() + QLatin1String("/file1.h");
|
const QString filePath1 = QDir::tempPath() + QLatin1String("/file1.h");
|
||||||
CppTools::Tests::TestCase::writeFile(filePath1, source1);
|
CppTools::Tests::TestCase::writeFile(filePath1, source1);
|
||||||
|
|
||||||
const QByteArray source2 =
|
|
||||||
"template<class _Elem, class _Traits>\n"
|
|
||||||
"class basic_streambuf {\n"
|
|
||||||
" typedef basic_streambuf<_Elem, _Traits> _Myt;\n"
|
|
||||||
"};\n"
|
|
||||||
"\n"
|
|
||||||
"template<class _Elem, class _Traits>\n"
|
|
||||||
"class ostreambuf_iterator {\n"
|
|
||||||
" typedef _Traits traits_type;\n"
|
|
||||||
" typedef basic_streambuf<_Elem, _Traits> streambuf_type;\n"
|
|
||||||
" typedef basic_ostream<_Elem, _Traits> ostream_type;\n"
|
|
||||||
"};\n"
|
|
||||||
;
|
|
||||||
const QString filePath2 = QDir::tempPath() + QLatin1String("/file2.h");
|
const QString filePath2 = QDir::tempPath() + QLatin1String("/file2.h");
|
||||||
CppTools::Tests::TestCase::writeFile(filePath2, source2);
|
CppTools::Tests::TestCase::writeFile(filePath2, source2);
|
||||||
|
|
||||||
@@ -1798,5 +1775,77 @@ void tst_CheckSymbols::test_checksymbols_infiniteLoop()
|
|||||||
TestCase::runCheckSymbols(document1, snapshot);
|
TestCase::runCheckSymbols(document1, snapshot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_CheckSymbols::test_checksymbols_infiniteLoop_data()
|
||||||
|
{
|
||||||
|
QTest::addColumn<QByteArray>("source1");
|
||||||
|
QTest::addColumn<QByteArray>("source2");
|
||||||
|
|
||||||
|
QTest::newRow("1")
|
||||||
|
<<
|
||||||
|
_("#include \"file2.h\"\n"
|
||||||
|
"\n"
|
||||||
|
"template<class _Elem, class _Traits>\n"
|
||||||
|
"class basic_ios {\n"
|
||||||
|
" typedef basic_ostream<_Elem, _Traits> _Myos;\n"
|
||||||
|
"};\n"
|
||||||
|
"\n"
|
||||||
|
"template<class _Elem, class _Traits>\n"
|
||||||
|
"class basic_ostream {\n"
|
||||||
|
" typedef basic_ostream<_Elem, _Traits> _Myt;\n"
|
||||||
|
" typedef ostreambuf_iterator<_Elem, _Traits> _Iter;\n"
|
||||||
|
"};\n")
|
||||||
|
<<
|
||||||
|
_("template<class _Elem, class _Traits>\n"
|
||||||
|
"class basic_streambuf {\n"
|
||||||
|
" typedef basic_streambuf<_Elem, _Traits> _Myt;\n"
|
||||||
|
"};\n"
|
||||||
|
"\n"
|
||||||
|
"template<class _Elem, class _Traits>\n"
|
||||||
|
"class ostreambuf_iterator {\n"
|
||||||
|
" typedef _Traits traits_type;\n"
|
||||||
|
" typedef basic_streambuf<_Elem, _Traits> streambuf_type;\n"
|
||||||
|
" typedef basic_ostream<_Elem, _Traits> ostream_type;\n"
|
||||||
|
"};\n")
|
||||||
|
;
|
||||||
|
|
||||||
|
QTest::newRow("2")
|
||||||
|
<<
|
||||||
|
_("#include \"file2.h\"\n"
|
||||||
|
"\n"
|
||||||
|
"template<class _Ty >\n"
|
||||||
|
"struct _List_base_types\n"
|
||||||
|
"{\n"
|
||||||
|
" typedef typename _Wrap_alloc<_Alloc>::template rebind<_Ty>::other _Alty;\n"
|
||||||
|
" typedef typename _Alty::template rebind<_Node>::other _Alnod_type;\n"
|
||||||
|
"};\n"
|
||||||
|
"\n"
|
||||||
|
"template<class _Alloc_types>\n"
|
||||||
|
"struct _List_alloc \n"
|
||||||
|
"{\n"
|
||||||
|
" const _Alloc_types::_Alnod_type& _Getal() const {}\n"
|
||||||
|
"};\n"
|
||||||
|
"\n"
|
||||||
|
"template<class _Ty, class _Alloc>\n"
|
||||||
|
"struct _List_buy : public _List_alloc< _List_base_types<_Ty> >\n"
|
||||||
|
"{\n"
|
||||||
|
" void foo()\n"
|
||||||
|
" {\n"
|
||||||
|
" this->_Getal().construct(1, 2);\n"
|
||||||
|
" this->_Getal().deallocate(0, 1);\n"
|
||||||
|
" }\n"
|
||||||
|
"};\n")
|
||||||
|
<<
|
||||||
|
_("template<class _Alloc>\n"
|
||||||
|
"struct _Wrap_alloc : public _Alloc\n"
|
||||||
|
"{\n"
|
||||||
|
" typedef _Alloc _Mybase;\n"
|
||||||
|
" template<class _Other> struct rebind { typedef _Wrap_alloc<_Other_alloc> other; };\n"
|
||||||
|
"\n"
|
||||||
|
" void deallocate(pointer _Ptr, size_type _Count) {}\n"
|
||||||
|
" void construct(value_type *_Ptr) {}\n"
|
||||||
|
"};\n")
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
QTEST_APPLESS_MAIN(tst_CheckSymbols)
|
QTEST_APPLESS_MAIN(tst_CheckSymbols)
|
||||||
#include "tst_checksymbols.moc"
|
#include "tst_checksymbols.moc"
|
||||||
|
|||||||
Reference in New Issue
Block a user