From b67ebf9ffce6bbba7952b36120f49d7abf956e66 Mon Sep 17 00:00:00 2001
From: Orgad Shaneh <orgad.shaneh@audiocodes.com>
Date: Fri, 22 May 2015 13:03:55 +0300
Subject: [PATCH] C++: Fix lookup for instantiation of using

Yet another std::vector issue...

Use-cases:
// Case 1
template<typename T>
using type = T;

// Case 2
struct Parent {
    template<typename T>
    using type = T;
};

// Case 3
template<typename T>
struct ParentT {
    template<typename DT>
    using type = DT;
};

struct Foo { int bar; };

void func()
{
    type<Foo> p1;
    Parent::type<Foo> p2;
    ParentT<Foo>::type<Foo> p3;
    // bar not highlighted
    p1.bar;
    p2.bar;
    p3.bar;
}

Task-number: QTCREATORBUG-14480
Change-Id: I9ab08ea7360a432c48eb4b85aa0d63e08d2464c1
Reviewed-by: Nikolai Kosjar <nikolai.kosjar@theqtcompany.com>
---
 src/libs/cplusplus/TypeResolver.cpp         |  6 +-
 src/plugins/cpptools/cppcompletion_test.cpp | 81 +++++++++++++++++++++
 2 files changed, 86 insertions(+), 1 deletion(-)

diff --git a/src/libs/cplusplus/TypeResolver.cpp b/src/libs/cplusplus/TypeResolver.cpp
index dab2016b38..c837c0f938 100644
--- a/src/libs/cplusplus/TypeResolver.cpp
+++ b/src/libs/cplusplus/TypeResolver.cpp
@@ -210,6 +210,10 @@ bool TypeResolver::findTypedef(const QList<LookupItem> &namedTypeItems, FullySpe
 {
     foreach (const LookupItem &it, namedTypeItems) {
         Symbol *declaration = it.declaration();
+        if (!declaration)
+            continue;
+        if (Template *specialization = declaration->asTemplate())
+            declaration = specialization->declaration();
         if (!declaration || (!declaration->isTypedef() && !declaration->type().isDecltype()))
             continue;
         if (visited.contains(declaration))
@@ -237,7 +241,7 @@ bool TypeResolver::findTypedef(const QList<LookupItem> &namedTypeItems, FullySpe
                 return true;
             }
         } else {
-            *type = declaration->type();
+            *type = it.type();
         }
 
         *scope = it.scope();
diff --git a/src/plugins/cpptools/cppcompletion_test.cpp b/src/plugins/cpptools/cppcompletion_test.cpp
index 00b796f0a8..cc98254c76 100644
--- a/src/plugins/cpptools/cppcompletion_test.cpp
+++ b/src/plugins/cpptools/cppcompletion_test.cpp
@@ -2917,6 +2917,87 @@ void CppToolsPlugin::test_completion_data()
         << QLatin1String("Foo")
         << QLatin1String("bar"));
 
+    QTest::newRow("template_using_instantiation") << _(
+            "template<typename _Tp>\n"
+            "using T = _Tp;\n"
+            "\n"
+            "struct Foo { int bar; };\n"
+            "\n"
+            "void func()\n"
+            "{\n"
+            "    T<Foo> p;\n"
+            "    @\n"
+            "}\n"
+    ) << _("p.") << (QStringList()
+        << QLatin1String("Foo")
+        << QLatin1String("bar"));
+
+    QTest::newRow("nested_template_using_instantiation") << _(
+            "struct Parent {\n"
+            "    template<typename _Tp>\n"
+            "    using T = _Tp;\n"
+            "};\n"
+            "\n"
+            "struct Foo { int bar; };\n"
+            "\n"
+            "void func()\n"
+            "{\n"
+            "    Parent::T<Foo> p;\n"
+            "    @;\n"
+            "}\n"
+     ) << _("p.") << (QStringList()
+        << QLatin1String("Foo")
+        << QLatin1String("bar"));
+
+    QTest::newRow("nested_template_using_instantiation_in_template_class") << _(
+            "template<typename ParentT>\n"
+            "struct Parent {\n"
+            "    template<typename _Tp>\n"
+            "    using T = _Tp;\n"
+            "};\n"
+            "\n"
+            "struct Foo { int bar; };\n"
+            "\n"
+            "void func()\n"
+            "{\n"
+            "    Parent<Foo>::T<Foo> p;\n"
+            "    @;\n"
+            "}\n"
+     ) << _("p.") << (QStringList()
+        << QLatin1String("Foo")
+        << QLatin1String("bar"));
+
+    QTest::newRow("recursive_nested_template_using_instantiation") << _(
+            "struct Foo { int bar; };\n"
+            "\n"
+            "struct A { typedef Foo value_type; };\n"
+            "\n"
+            "template<typename T>\n"
+            "struct Traits\n"
+            "{\n"
+            "    typedef Foo value_type;\n"
+            "\n"
+            "    template<typename _Tp>\n"
+            "    using U = T;\n"
+            "};\n"
+            "\n"
+            "template<typename T>\n"
+            "struct Temp\n"
+            "{\n"
+            "    typedef Traits<T> TraitsT;\n"
+            "    typedef typename T::value_type value_type;\n"
+            "    typedef typename TraitsT::template U<Foo> rebind;\n"
+            "};\n"
+            "\n"
+            "void func()\n"
+            "{\n"
+            "    typename Temp<typename Temp<A>::rebind>::value_type p;\n"
+            "    @\n"
+            "}\n"
+    ) << _("p.") << (QStringList()
+        << QLatin1String("Foo")
+        << QLatin1String("bar"));
+
     QTest::newRow("qualified_name_in_nested_type") << _(
             "template<typename _Tp>\n"
             "struct Temp {\n"
-- 
GitLab