From e58906a9ed718b0e65a0f805c165e7bacf54d936 Mon Sep 17 00:00:00 2001
From: Nikolai Kosjar <nikolai.kosjar@digia.com>
Date: Fri, 18 Oct 2013 10:25:52 +0200
Subject: [PATCH] C++: Limit typedef resolving depth

This reverts commit 5be56c0 except for its tests. While it fixed the
problem described in the bug report, it also introduced regressions.

For now, we use a hard limit.

Change-Id: I19a85be454e3d7969371707e3eb1c3d42a16ecee
Reviewed-by: Przemyslaw Gorszkowski <pgorszkowski@gmail.com>
Reviewed-by: Erik Verbruggen <erik.verbruggen@digia.com>
---
 src/libs/cplusplus/ResolveExpression.cpp    | 33 ++-----
 src/plugins/cpptools/cppcompletion_test.cpp | 98 ++++++++++-----------
 src/plugins/cpptools/cpptoolsplugin.h       |  5 +-
 3 files changed, 57 insertions(+), 79 deletions(-)

diff --git a/src/libs/cplusplus/ResolveExpression.cpp b/src/libs/cplusplus/ResolveExpression.cpp
index fd144a4e611..fd29b1972bc 100644
--- a/src/libs/cplusplus/ResolveExpression.cpp
+++ b/src/libs/cplusplus/ResolveExpression.cpp
@@ -886,23 +886,12 @@ public:
     {
         QSet<Symbol *> visited;
         _binding = binding;
-        while (NamedType *namedTy = getNamedType(*type)) {
-            const Name *name = namedTy->name();
-            Scope *templateScope = *scope;
-            if (const QualifiedNameId *q = name->asQualifiedNameId()) {
-                do {
-                    const TemplateNameId *templateNameId = 0;
-                    name = q->name();
-                    if (name && (templateNameId = name->asTemplateNameId()))
-                        resolve(templateNameId, templateScope, binding);
-
-                    name = q->base();
-                    if (name && (templateNameId = name->asTemplateNameId()))
-                        resolve(templateNameId, templateScope, binding);
-                } while ((name && (q = name->asQualifiedNameId())));
-            } else if (const TemplateNameId *templateNameId = name->asTemplateNameId()) {
-                resolve(templateNameId, templateScope, binding);
-            }
+        // Use a hard limit when trying to resolve typedefs. Typedefs in templates can refer to
+        // each other, each time enhancing the template argument and thus making it impossible to
+        // use an "alreadyResolved" container. FIXME: We might overcome this by resolving the
+        // template parameters.
+        unsigned maxDepth = 15;
+        for (NamedType *namedTy = 0; maxDepth && (namedTy = getNamedType(*type)); --maxDepth) {
             QList<LookupItem> namedTypeItems = getNamedTypeItems(namedTy->name(), *scope, _binding);
 
 #ifdef DEBUG_LOOKUP
@@ -915,16 +904,6 @@ public:
     }
 
 private:
-    void resolve(const TemplateNameId *templateNameId, Scope *templateScope,
-                 ClassOrNamespace *binding)
-    {
-        for (unsigned i = 0; i < templateNameId->templateArgumentCount(); ++i) {
-            FullySpecifiedType &templateArgumentType
-                    = const_cast<FullySpecifiedType &>(templateNameId->templateArgumentAt(i));
-            resolve(&templateArgumentType, &templateScope, binding);
-        }
-    }
-
     NamedType *getNamedType(FullySpecifiedType& type) const
     {
         NamedType *namedTy = type->asNamedType();
diff --git a/src/plugins/cpptools/cppcompletion_test.cpp b/src/plugins/cpptools/cppcompletion_test.cpp
index 856f96d0049..3eed35b5074 100644
--- a/src/plugins/cpptools/cppcompletion_test.cpp
+++ b/src/plugins/cpptools/cppcompletion_test.cpp
@@ -2070,6 +2070,55 @@ void CppToolsPlugin::test_completion_recursive_using_typedef_declarations()
     QCOMPARE(completions.size(), 0);
 }
 
+void CppToolsPlugin::test_completion_recursive_typedefs_in_templates1()
+{
+    const QByteArray source =
+            "template<typename From>\n"
+            "struct simplify_type {\n"
+            "    typedef From SimpleType;\n"
+            "};\n"
+            "\n"
+            "template<class To, class From>\n"
+            "struct cast_retty {\n"
+            "    typedef typename cast_retty_wrap<To, From,\n"
+            "                     typename simplify_type<From>::SimpleType>::ret_type ret_type;\n"
+            "};\n"
+            "\n"
+            "template<class To, class From, class SimpleFrom>\n"
+            "struct cast_retty_wrap {\n"
+            "    typedef typename cast_retty<To, SimpleFrom>::ret_type ret_type;\n"
+            "};\n"
+            "\n"
+            "void f()\n"
+            "{\n"
+            "    @;\n"
+            "}\n"
+            ;
+    CompletionTestCase test(source, "cast_retty<T1, T2>::ret_type.");
+
+    const QStringList completions = test.getCompletions();
+    QCOMPARE(completions.size(), 0);
+}
+
+void CppToolsPlugin::test_completion_recursive_typedefs_in_templates2()
+{
+    const QByteArray source =
+            "template<class T>\n"
+            "struct recursive {\n"
+            "  typedef typename recursive<T>::ret_type ret_type;\n"
+            "};\n"
+            "\n"
+            "void f()\n"
+            "{\n"
+            "    @;\n"
+            "}\n"
+            ;
+    CompletionTestCase test(source, "recursive<T1>::ret_type.foo");
+
+    const QStringList completions = test.getCompletions();
+    QCOMPARE(completions.size(), 0);
+}
+
 void CppToolsPlugin::test_completion_prefix_first_QTCREATORBUG_8737()
 {
     const QByteArray source =
@@ -2740,55 +2789,6 @@ void CppToolsPlugin::test_completion_template_parameter_defined_inside_scope_of_
     QVERIFY(completions.contains(QLatin1String("bar")));
 }
 
-void CppToolsPlugin::test_completion_recursive_typedefs_in_templates1()
-{
-    const QByteArray source =
-            "template<typename From>\n"
-            "struct simplify_type {\n"
-            "    typedef From SimpleType;\n"
-            "};\n"
-            "\n"
-            "template<class To, class From>\n"
-            "struct cast_retty {\n"
-            "    typedef typename cast_retty_wrap<To, From,\n"
-            "                     typename simplify_type<From>::SimpleType>::ret_type ret_type;\n"
-            "};\n"
-            "\n"
-            "template<class To, class From, class SimpleFrom>\n"
-            "struct cast_retty_wrap {\n"
-            "    typedef typename cast_retty<To, SimpleFrom>::ret_type ret_type;\n"
-            "};\n"
-            "\n"
-            "void f()\n"
-            "{\n"
-            "    @;\n"
-            "}\n"
-            ;
-    CompletionTestCase test(source, "cast_retty<T1, T2>::ret_type.");
-
-    const QStringList completions = test.getCompletions();
-    QCOMPARE(completions.size(), 0);
-}
-
-void CppToolsPlugin::test_completion_recursive_typedefs_in_templates2()
-{
-    const QByteArray source =
-            "template<class T>\n"
-            "struct recursive {\n"
-            "  typedef typename recursive<To>::ret_type ret_type;\n"
-            "};\n"
-            "\n"
-            "void f()\n"
-            "{\n"
-            "    @;\n"
-            "}\n"
-            ;
-    CompletionTestCase test(source, "recursive<T1>::ret_type.foo");
-
-    const QStringList completions = test.getCompletions();
-    QCOMPARE(completions.size(), 0);
-}
-
 void CppToolsPlugin::test_completion_signals_hide_QPrivateSignal()
 {
     const QByteArray source =
diff --git a/src/plugins/cpptools/cpptoolsplugin.h b/src/plugins/cpptools/cpptoolsplugin.h
index 2c30baf90fa..d9633708dc9 100644
--- a/src/plugins/cpptools/cpptoolsplugin.h
+++ b/src/plugins/cpptools/cpptoolsplugin.h
@@ -153,6 +153,8 @@ private slots:
     void test_completion_recursive_using_declarations1();
     void test_completion_recursive_using_declarations2();
     void test_completion_recursive_using_typedef_declarations();
+    void test_completion_recursive_typedefs_in_templates1();
+    void test_completion_recursive_typedefs_in_templates2();
     void test_completion_prefix_first_QTCREATORBUG_8737();
     void test_completion_prefix_first_QTCREATORBUG_9236();
 
@@ -184,9 +186,6 @@ private slots:
     void test_completion_local_type_and_member_5();
     void test_completion_local_type_and_member_6();
 
-    void test_completion_recursive_typedefs_in_templates1();
-    void test_completion_recursive_typedefs_in_templates2();
-
     void test_completion_signals_hide_QPrivateSignal();
 
     void test_format_pointerdeclaration_in_simpledeclarations();
-- 
GitLab