From efb600665d3cb277d330974bcfd90a1da8dc6395 Mon Sep 17 00:00:00 2001
From: Roberto Raggi <roberto.raggi@nokia.com>
Date: Thu, 12 Aug 2010 12:18:49 +0200
Subject: [PATCH] Remember the T_TEMPLATE token we use to force the parser to
 recognize a template-id.

---
 src/plugins/cppeditor/cppchecksymbols.cpp | 46 ++++++++++++-----------
 src/shared/cplusplus/AST.cpp              |  4 ++
 src/shared/cplusplus/AST.h                |  4 +-
 src/shared/cplusplus/ASTClone.cpp         |  1 +
 src/shared/cplusplus/ASTMatcher.cpp       |  2 +
 src/shared/cplusplus/Parser.cpp           |  7 ++--
 src/shared/cplusplus/Parser.h             |  2 +-
 tests/manual/cplusplus-dump/dumpers.inc   |  4 +-
 8 files changed, 43 insertions(+), 27 deletions(-)

diff --git a/src/plugins/cppeditor/cppchecksymbols.cpp b/src/plugins/cppeditor/cppchecksymbols.cpp
index 6d8a2e3905d..add8b3fbe3a 100644
--- a/src/plugins/cppeditor/cppchecksymbols.cpp
+++ b/src/plugins/cppeditor/cppchecksymbols.cpp
@@ -483,17 +483,8 @@ bool CheckSymbols::visit(NamedTypeSpecifierAST *)
 bool CheckSymbols::visit(ElaboratedTypeSpecifierAST *ast)
 {
     accept(ast->attribute_list);
-
-    if (ast->name) {
-        if (const Name *name = ast->name->name) {
-            if (name->isNameId() || name->isTemplateNameId()) {
-                addUse(ast->name, Use::Type);
-                return false;
-            }
-        }
-    }
-
     accept(ast->name);
+    addUse(ast->name, Use::Type);
     return false;
 }
 
@@ -678,7 +669,7 @@ bool CheckSymbols::visit(DestructorNameAST *ast)
 bool CheckSymbols::visit(QualifiedNameAST *ast)
 {
     if (ast->name) {
-        ClassOrNamespace *b = 0;
+        ClassOrNamespace *binding = 0;
         if (NestedNameSpecifierListAST *it = ast->nested_name_specifier_list) {
             NestedNameSpecifierAST *nested_name_specifier = it->value;
             if (NameAST *class_or_namespace_name = nested_name_specifier->class_or_namespace_name) { // ### remove shadowing
@@ -687,29 +678,39 @@ bool CheckSymbols::visit(QualifiedNameAST *ast)
                     accept(template_id->template_argument_list);
 
                 const Name *name = class_or_namespace_name->name;
-                b = _context.lookupType(name, enclosingScope());
-                addType(b, class_or_namespace_name);
+                binding = _context.lookupType(name, enclosingScope());
+                addType(binding, class_or_namespace_name);
 
-                for (it = it->next; b && it; it = it->next) {
+                for (it = it->next; it; it = it->next) {
                     NestedNameSpecifierAST *nested_name_specifier = it->value;
 
                     if (NameAST *class_or_namespace_name = nested_name_specifier->class_or_namespace_name) {
-                        if (TemplateIdAST *template_id = class_or_namespace_name->asTemplateId())
-                            accept(template_id->template_argument_list);
+                        if (TemplateIdAST *template_id = class_or_namespace_name->asTemplateId()) {
+                            if (template_id->template_token) {
+                                addUse(template_id, Use::Type);
+                                binding = 0; // there's no way we can find a binding.
+                            }
 
-                        b = b->findType(class_or_namespace_name->name);
-                        addType(b, class_or_namespace_name);
+                            accept(template_id->template_argument_list);
+                            if (! binding)
+                                continue;
+                        }
+
+                        if (binding) {
+                            binding = binding->findType(class_or_namespace_name->name);
+                            addType(binding, class_or_namespace_name);
+                        }
                     }
                 }
             }
         }
 
-        if (b && ast->unqualified_name) {
+        if (binding && ast->unqualified_name) {
             if (ast->unqualified_name->asDestructorName() != 0) {
-                if (hasVirtualDestructor(b))
+                if (hasVirtualDestructor(binding))
                     addUse(ast->unqualified_name, Use::VirtualMethod);
             } else {
-                addTypeOrStatic(b->find(ast->unqualified_name->name), ast->unqualified_name);
+                addTypeOrStatic(binding->find(ast->unqualified_name->name), ast->unqualified_name);
             }
         }
     }
@@ -805,6 +806,9 @@ void CheckSymbols::addUse(NameAST *ast, Use::Kind kind)
     if (DestructorNameAST *dtor = ast->asDestructorName())
         startToken = dtor->identifier_token;
 
+    else if (TemplateIdAST *templ = ast->asTemplateId())
+        startToken = templ->identifier_token;
+
     addUse(startToken, kind);
 }
 
diff --git a/src/shared/cplusplus/AST.cpp b/src/shared/cplusplus/AST.cpp
index 3d5f80a7f53..bfe4d2d325c 100644
--- a/src/shared/cplusplus/AST.cpp
+++ b/src/shared/cplusplus/AST.cpp
@@ -3687,6 +3687,8 @@ unsigned TemplateDeclarationAST::lastToken() const
 /** \generated */
 unsigned TemplateIdAST::firstToken() const
 {
+    if (template_token)
+        return template_token;
     if (identifier_token)
         return identifier_token;
     if (less_token)
@@ -3711,6 +3713,8 @@ unsigned TemplateIdAST::lastToken() const
         return less_token + 1;
     if (identifier_token)
         return identifier_token + 1;
+    if (template_token)
+        return template_token + 1;
     return 0;
 }
 
diff --git a/src/shared/cplusplus/AST.h b/src/shared/cplusplus/AST.h
index 227eb21483b..8db76fb4597 100644
--- a/src/shared/cplusplus/AST.h
+++ b/src/shared/cplusplus/AST.h
@@ -2214,6 +2214,7 @@ protected:
 class CPLUSPLUS_EXPORT TemplateIdAST: public NameAST
 {
 public:
+    unsigned template_token;
     unsigned identifier_token;
     unsigned less_token;
     ExpressionListAST *template_argument_list;
@@ -2221,7 +2222,8 @@ public:
 
 public:
     TemplateIdAST()
-        : identifier_token(0)
+        : template_token(0)
+        , identifier_token(0)
         , less_token(0)
         , template_argument_list(0)
         , greater_token(0)
diff --git a/src/shared/cplusplus/ASTClone.cpp b/src/shared/cplusplus/ASTClone.cpp
index 996d4dbda5b..9b837e1384e 100644
--- a/src/shared/cplusplus/ASTClone.cpp
+++ b/src/shared/cplusplus/ASTClone.cpp
@@ -802,6 +802,7 @@ DestructorNameAST *DestructorNameAST::clone(MemoryPool *pool) const
 TemplateIdAST *TemplateIdAST::clone(MemoryPool *pool) const
 {
     TemplateIdAST *ast = new (pool) TemplateIdAST;
+    ast->template_token = template_token;
     ast->identifier_token = identifier_token;
     ast->less_token = less_token;
     for (ExpressionListAST *iter = template_argument_list, **ast_iter = &ast->template_argument_list;
diff --git a/src/shared/cplusplus/ASTMatcher.cpp b/src/shared/cplusplus/ASTMatcher.cpp
index 2b4c88bf938..5737bf0f537 100644
--- a/src/shared/cplusplus/ASTMatcher.cpp
+++ b/src/shared/cplusplus/ASTMatcher.cpp
@@ -1347,6 +1347,8 @@ bool ASTMatcher::match(TemplateIdAST *node, TemplateIdAST *pattern)
     (void) node;
     (void) pattern;
 
+    pattern->template_token = node->template_token;
+
     pattern->identifier_token = node->identifier_token;
 
     pattern->less_token = node->less_token;
diff --git a/src/shared/cplusplus/Parser.cpp b/src/shared/cplusplus/Parser.cpp
index 07b0a018a50..ad20ef7af4f 100644
--- a/src/shared/cplusplus/Parser.cpp
+++ b/src/shared/cplusplus/Parser.cpp
@@ -419,14 +419,14 @@ bool Parser::parseClassOrNamespaceName(NameAST *&node)
         }
     } else if (LA() == T_TEMPLATE) {
         unsigned template_token = consumeToken();
-        if (parseTemplateId(node))
+        if (parseTemplateId(node, template_token))
             return true;
         rewind(template_token);
     }
     return false;
 }
 
-bool Parser::parseTemplateId(NameAST *&node)
+bool Parser::parseTemplateId(NameAST *&node, unsigned template_token)
 {
     DEBUG_THIS_RULE();
 
@@ -434,6 +434,7 @@ bool Parser::parseTemplateId(NameAST *&node)
 
     if (LA() == T_IDENTIFIER && LA(2) == T_LESS) {
         TemplateIdAST *ast = new (_pool) TemplateIdAST;
+        ast->template_token = template_token;
         ast->identifier_token = consumeToken();
         ast->less_token = consumeToken();
         if (LA() == T_GREATER || parseTemplateArgumentList(
@@ -2642,7 +2643,7 @@ bool Parser::parseUnqualifiedName(NameAST *&node, bool acceptTemplateId)
          return true;
     } else if (LA() == T_TEMPLATE) {
         unsigned template_token = consumeToken();
-        if (parseTemplateId(node))
+        if (parseTemplateId(node, template_token))
             return true;
         rewind(template_token);
     }
diff --git a/src/shared/cplusplus/Parser.h b/src/shared/cplusplus/Parser.h
index 4b19f1cf10f..11743346a4e 100644
--- a/src/shared/cplusplus/Parser.h
+++ b/src/shared/cplusplus/Parser.h
@@ -147,7 +147,7 @@ public:
     bool parseMemInitializerList(MemInitializerListAST *&node);
     bool parseMemberSpecification(DeclarationAST *&node);
     bool parseMultiplicativeExpression(ExpressionAST *&node);
-    bool parseTemplateId(NameAST *&node);
+    bool parseTemplateId(NameAST *&node, unsigned template_token = 0);
     bool parseClassOrNamespaceName(NameAST *&node);
     bool parseNameId(NameAST *&node);
     bool parseName(NameAST *&node, bool acceptTemplateId = true);
diff --git a/tests/manual/cplusplus-dump/dumpers.inc b/tests/manual/cplusplus-dump/dumpers.inc
index 1ac8ef9eb35..4d090004ad9 100644
--- a/tests/manual/cplusplus-dump/dumpers.inc
+++ b/tests/manual/cplusplus-dump/dumpers.inc
@@ -771,11 +771,13 @@ virtual bool visit(DestructorNameAST *ast)
 
 virtual bool visit(TemplateIdAST *ast)
 {
+    if (ast->template_token)
+        terminal(ast->template_token, ast);
     if (ast->identifier_token)
         terminal(ast->identifier_token, ast);
     if (ast->less_token)
         terminal(ast->less_token, ast);
-    for (TemplateArgumentListAST *iter = ast->template_argument_list; iter; iter = iter->next)
+    for (ExpressionListAST *iter = ast->template_argument_list; iter; iter = iter->next)
         nonterminal(iter->value);
     if (ast->greater_token)
         terminal(ast->greater_token, ast);
-- 
GitLab