From 05984e71fc1d93dc65bc5aab42b5edea8f66601e Mon Sep 17 00:00:00 2001
From: Roberto Raggi <roberto.raggi@nokia.com>
Date: Thu, 6 May 2010 14:01:38 +0200
Subject: [PATCH] Refactor a bit the lookup, it should simplify template
 instantiation.

---
 src/libs/cplusplus/GenTemplateInstance.cpp | 32 +++++++++-
 src/libs/cplusplus/GenTemplateInstance.h   |  8 +--
 src/libs/cplusplus/LookupContext.cpp       | 69 ++++++++++++++++++----
 src/libs/cplusplus/LookupContext.h         | 20 +++++--
 src/libs/cplusplus/ResolveExpression.cpp   | 44 +-------------
 5 files changed, 110 insertions(+), 63 deletions(-)

diff --git a/src/libs/cplusplus/GenTemplateInstance.cpp b/src/libs/cplusplus/GenTemplateInstance.cpp
index bb6afc6655e..a9191461e13 100644
--- a/src/libs/cplusplus/GenTemplateInstance.cpp
+++ b/src/libs/cplusplus/GenTemplateInstance.cpp
@@ -369,11 +369,37 @@ GenTemplateInstance::GenTemplateInstance(Control *control, const Substitution &s
       _substitution(substitution)
 { }
 
-FullySpecifiedType GenTemplateInstance::operator()(Symbol *symbol)
+FullySpecifiedType GenTemplateInstance::gen(Symbol *symbol)
 {
     ApplySubstitution o(_control, symbol, _substitution);
     return o.apply(symbol->type());
 }
 
-Control *GenTemplateInstance::control() const
-{ return _control; }
+FullySpecifiedType GenTemplateInstance::instantiate(const Name *className, Symbol *candidate, Control *control)
+{
+    if (className) {
+        if (const TemplateNameId *templId = className->asTemplateNameId()) {
+            if (Class *klass = candidate->enclosingSymbol()->asClass()) {
+                GenTemplateInstance::Substitution subst;
+
+                for (unsigned i = 0; i < templId->templateArgumentCount(); ++i) {
+                    FullySpecifiedType templArgTy = templId->templateArgumentAt(i);
+
+                    if (i < klass->templateParameterCount()) {
+                        const Name *templArgName = klass->templateParameterAt(i)->name();
+
+                        if (templArgName && templArgName->identifier()) {
+                            const Identifier *templArgId = templArgName->identifier();
+                            subst.append(qMakePair(templArgId, templArgTy));
+                        }
+                    }
+                }
+
+                GenTemplateInstance inst(control, subst);
+                return inst.gen(candidate);
+            }
+        }
+    }
+
+    return candidate->type();
+}
diff --git a/src/libs/cplusplus/GenTemplateInstance.h b/src/libs/cplusplus/GenTemplateInstance.h
index b667cc2ab41..8d186341dcb 100644
--- a/src/libs/cplusplus/GenTemplateInstance.h
+++ b/src/libs/cplusplus/GenTemplateInstance.h
@@ -47,11 +47,11 @@ public:
     typedef QList< QPair<const Identifier *, FullySpecifiedType> > Substitution;
 
 public:
-    GenTemplateInstance(Control *control, const Substitution &substitution);
-
-    FullySpecifiedType operator()(Symbol *symbol);
+    static FullySpecifiedType instantiate(const Name *className, Symbol *candidate, Control *control);
 
-    Control *control() const;
+private:
+    GenTemplateInstance(Control *control, const Substitution &substitution);
+    FullySpecifiedType gen(Symbol *symbol);
 
 private:
     Symbol *_symbol;
diff --git a/src/libs/cplusplus/LookupContext.cpp b/src/libs/cplusplus/LookupContext.cpp
index 74612de3ba0..33cab4103b5 100644
--- a/src/libs/cplusplus/LookupContext.cpp
+++ b/src/libs/cplusplus/LookupContext.cpp
@@ -31,6 +31,7 @@
 #include "ResolveExpression.h"
 #include "Overview.h"
 #include "CppBindings.h"
+#include "GenTemplateInstance.h"
 
 #include <CoreTypes.h>
 #include <Symbols.h>
@@ -40,6 +41,7 @@
 #include <Control.h>
 
 #include <QtDebug>
+#include <cxxabi.h>
 
 //#define CPLUSPLUS_NO_LAZY_LOOKUP
 
@@ -197,7 +199,7 @@ QList<Symbol *> LookupContext::lookup(const Name *name, Scope *scope) const
 
     for (; scope; scope = scope->enclosingScope()) {
         if (id && scope->isBlockScope()) {
-            ClassOrNamespace::lookup_helper(name, scope, &candidates);
+            bindings()->lookup_helper(name, scope, &candidates, /*templateId = */ 0);
 
             if (! candidates.isEmpty())
                 break; // it's a local.
@@ -221,7 +223,7 @@ QList<Symbol *> LookupContext::lookup(const Name *name, Scope *scope) const
 
         } else if (scope->isFunctionScope()) {
             Function *fun = scope->owner()->asFunction();
-            ClassOrNamespace::lookup_helper(name, fun->arguments(), &candidates);
+            bindings()->lookup_helper(name, fun->arguments(), &candidates, /*templateId = */ 0);
             if (! candidates.isEmpty())
                 break; // it's a formal argument.
 
@@ -244,7 +246,7 @@ QList<Symbol *> LookupContext::lookup(const Name *name, Scope *scope) const
 
         } else if (scope->isObjCMethodScope()) {
             ObjCMethod *method = scope->owner()->asObjCMethod();
-            ClassOrNamespace::lookup_helper(name, method->arguments(), &candidates);
+            bindings()->lookup_helper(name, method->arguments(), &candidates, /*templateId = */ 0);
             if (! candidates.isEmpty())
                 break; // it's a formal argument.
 
@@ -261,7 +263,7 @@ QList<Symbol *> LookupContext::lookup(const Name *name, Scope *scope) const
 }
 
 ClassOrNamespace::ClassOrNamespace(CreateBindings *factory, ClassOrNamespace *parent)
-    : _factory(factory), _parent(parent)
+    : _factory(factory), _parent(parent), _templateId(0)
 {
 }
 
@@ -323,7 +325,7 @@ QList<Symbol *> ClassOrNamespace::lookup(const Name *name)
     QSet<ClassOrNamespace *> processed;
     ClassOrNamespace *binding = this;
     do {
-        lookup_helper(name, binding, &result, &processed);
+        lookup_helper(name, binding, &result, &processed, /*templateId = */ 0);
         binding = binding->_parent;
     } while (binding);
 
@@ -332,7 +334,8 @@ QList<Symbol *> ClassOrNamespace::lookup(const Name *name)
 
 void ClassOrNamespace::lookup_helper(const Name *name, ClassOrNamespace *binding,
                                      QList<Symbol *> *result,
-                                     QSet<ClassOrNamespace *> *processed)
+                                     QSet<ClassOrNamespace *> *processed,
+                                     const TemplateNameId *templateId)
 {
     if (! binding)
         return;
@@ -340,21 +343,30 @@ void ClassOrNamespace::lookup_helper(const Name *name, ClassOrNamespace *binding
     else if (! processed->contains(binding)) {
         processed->insert(binding);
 
+        //Overview oo;
+        //qDebug() << "search for:" << oo(name) << "template:" << oo(templateId) << "b:" << oo(binding->_templateId);
+
         foreach (Symbol *s, binding->symbols()) {
             if (ScopedSymbol *scoped = s->asScopedSymbol())
-                lookup_helper(name, scoped->members(), result);
+                _factory->lookup_helper(name, scoped->members(), result, templateId);
         }
 
         foreach (Enum *e, binding->enums())
-            lookup_helper(name, e->members(), result);
+            _factory->lookup_helper(name, e->members(), result, templateId);
 
         foreach (ClassOrNamespace *u, binding->usings())
-            lookup_helper(name, u, result, processed);
+            lookup_helper(name, u, result, processed, binding->_templateId);
+
+        //qDebug() << "=======" << oo(name) << "template:" << oo(binding->_templateId);
     }
 }
 
-void ClassOrNamespace::lookup_helper(const Name *name, Scope *scope, QList<Symbol *> *result)
+void CreateBindings::lookup_helper(const Name *name, Scope *scope,
+                                   QList<Symbol *> *result,
+                                   const TemplateNameId *templateId)
 {
+    Q_UNUSED(templateId);
+
     if (! name) {
         return;
 
@@ -364,6 +376,7 @@ void ClassOrNamespace::lookup_helper(const Name *name, Scope *scope, QList<Symbo
                 continue;
             else if (! s->name()->isEqualTo(op))
                 continue;
+
             result->append(s);
         }
 
@@ -382,6 +395,7 @@ void ClassOrNamespace::lookup_helper(const Name *name, Scope *scope, QList<Symbo
 #endif
                 continue;
             }
+
             result->append(s);
         }
 
@@ -507,7 +521,28 @@ ClassOrNamespace *ClassOrNamespace::nestedClassOrNamespace(const Name *name) con
     if (it == _classOrNamespaces.end())
         return 0;
 
-    return it->second;
+    ClassOrNamespace *c = it->second;
+
+    if (const TemplateNameId *templId = name->asTemplateNameId()) {
+        Overview oo;
+        qDebug() << "search for:" << oo(templId);
+
+        foreach (ClassOrNamespace *i, c->_instantiations) {
+            if (templId->isEqualTo(i->_templateId)) {
+                qDebug() << "*** got a match";
+                return i;
+            }
+        }
+
+        ClassOrNamespace *i = _factory->allocClassOrNamespace(c);
+        i->_templateId = templId;
+        i->_usings.append(c);
+        c->_instantiations.append(i);
+        qDebug() << "created a new instantiation" << i;
+        return i;
+    }
+
+    return c;
 }
 
 void ClassOrNamespace::flush()
@@ -566,6 +601,11 @@ ClassOrNamespace *ClassOrNamespace::findOrCreate(const Name *name)
 
         if (! e) {
             e = _factory->allocClassOrNamespace(this);
+
+            if (const TemplateNameId *templId = name->asTemplateNameId()) {
+                Overview oo;
+                qDebug() << "find or create:" << oo(templId);
+            }
             _classOrNamespaces[name] = e;
         }
 
@@ -578,6 +618,7 @@ ClassOrNamespace *ClassOrNamespace::findOrCreate(const Name *name)
 CreateBindings::CreateBindings(Document::Ptr thisDocument, const Snapshot &snapshot)
     : _snapshot(snapshot)
 {
+    _control = new Control();
     _globalNamespace = allocClassOrNamespace(/*parent = */ 0);
     _currentClassOrNamespace = _globalNamespace;
 
@@ -587,6 +628,7 @@ CreateBindings::CreateBindings(Document::Ptr thisDocument, const Snapshot &snaps
 CreateBindings::~CreateBindings()
 {
     qDeleteAll(_entities);
+    delete _control;
 }
 
 ClassOrNamespace *CreateBindings::switchCurrentEntity(ClassOrNamespace *classOrNamespace)
@@ -639,6 +681,11 @@ void CreateBindings::process(Symbol *symbol)
 #endif
 }
 
+Control *CreateBindings::control() const
+{
+    return _control;
+}
+
 ClassOrNamespace *CreateBindings::allocClassOrNamespace(ClassOrNamespace *parent)
 {
     ClassOrNamespace *e = new ClassOrNamespace(this, parent);
diff --git a/src/libs/cplusplus/LookupContext.h b/src/libs/cplusplus/LookupContext.h
index 3d073aa6bbd..20188c6d21d 100644
--- a/src/libs/cplusplus/LookupContext.h
+++ b/src/libs/cplusplus/LookupContext.h
@@ -60,9 +60,6 @@ public:
     ClassOrNamespace *findClassOrNamespace(const Name *name);
     ClassOrNamespace *findClassOrNamespace(const QList<const Name *> &path);
 
-    /// \internal
-    static void lookup_helper(const Name *name, Scope *scope, QList<Symbol *> *result);
-
 private:
     /// \internal
     void flush();
@@ -78,7 +75,8 @@ private:
 
     void lookup_helper(const Name *name, ClassOrNamespace *binding,
                        QList<Symbol *> *result,
-                       QSet<ClassOrNamespace *> *processed);
+                       QSet<ClassOrNamespace *> *processed,
+                       const TemplateNameId *templateId);
 
     ClassOrNamespace *lookupClassOrNamespace_helper(const Name *name, QSet<ClassOrNamespace *> *processed);
     ClassOrNamespace *findClassOrNamespace_helper(const Name *name, QSet<ClassOrNamespace *> *processed);
@@ -99,6 +97,12 @@ private:
     QList<Enum *> _enums;
     QList<Symbol *> _todo;
 
+    // it's an instantiation.
+    const TemplateNameId *_templateId;
+
+    // templates
+    QList<ClassOrNamespace *> _instantiations;
+
     friend class CreateBindings;
 };
 
@@ -121,6 +125,13 @@ public:
     /// \internal
     ClassOrNamespace *allocClassOrNamespace(ClassOrNamespace *parent);
 
+    /// \internal
+    Control *control() const;
+
+    /// \internal
+    void lookup_helper(const Name *name, Scope *scope, QList<Symbol *> *result,
+                       const TemplateNameId *templateId);
+
 protected:
     using SymbolVisitor::visit;
 
@@ -150,6 +161,7 @@ protected:
     virtual bool visit(ObjCMethod *);
 
 private:
+    Control *_control;
     Snapshot _snapshot;
     QSet<Namespace *> _processed;
     QList<ClassOrNamespace *> _entities;
diff --git a/src/libs/cplusplus/ResolveExpression.cpp b/src/libs/cplusplus/ResolveExpression.cpp
index 3f1a72eced7..89c4b5ae271 100644
--- a/src/libs/cplusplus/ResolveExpression.cpp
+++ b/src/libs/cplusplus/ResolveExpression.cpp
@@ -679,29 +679,7 @@ ResolveExpression::resolveMemberExpression(const QList<LookupItem> &baseResults,
 
 FullySpecifiedType ResolveExpression::instantiate(const Name *className, Symbol *candidate) const
 {
-    if (const TemplateNameId *templId = className->asTemplateNameId()) {
-        if (Class *klass = candidate->enclosingSymbol()->asClass()) {
-            GenTemplateInstance::Substitution subst;
-
-            for (unsigned i = 0; i < templId->templateArgumentCount(); ++i) {
-                FullySpecifiedType templArgTy = templId->templateArgumentAt(i);
-
-                if (i < klass->templateParameterCount()) {
-                    const Name *templArgName = klass->templateParameterAt(i)->name();
-
-                    if (templArgName && templArgName->identifier()) {
-                        const Identifier *templArgId = templArgName->identifier();
-                        subst.append(qMakePair(templArgId, templArgTy));
-                    }
-                }
-            }
-
-            GenTemplateInstance inst(_context.control(), subst);
-            return inst(candidate);
-        }
-    }
-
-    return candidate->type();
+    return GenTemplateInstance::instantiate(className, candidate, _context.control());
 }
 
 QList<LookupItem>
@@ -728,24 +706,8 @@ ResolveExpression::resolveMember(const Name *memberName, Class *klass,
         if (const QualifiedNameId *q = className->asQualifiedNameId())
             unqualifiedNameId = q->unqualifiedNameId();
 
-        if (const TemplateNameId *templId = unqualifiedNameId->asTemplateNameId()) {
-            GenTemplateInstance::Substitution subst;
-
-            for (unsigned i = 0; i < templId->templateArgumentCount(); ++i) {
-                FullySpecifiedType templArgTy = templId->templateArgumentAt(i);
-
-                if (i < klass->templateParameterCount()) {
-                    const Name *templArgName = klass->templateParameterAt(i)->name();
-                    if (templArgName && templArgName->identifier()) {
-                        const Identifier *templArgId = templArgName->identifier();
-                        subst.append(qMakePair(templArgId, templArgTy));
-                    }
-                }
-            }
-
-            GenTemplateInstance inst(_context.control(), subst);
-            ty = inst(candidate);
-        }
+        if (const TemplateNameId *templId = unqualifiedNameId->asTemplateNameId())
+            ty = GenTemplateInstance::instantiate(templId, candidate, _context.control());
 
         results.append(LookupItem(ty, candidate));
     }
-- 
GitLab