From 1f1c899cc083c55daf7cc4591bf92f6103fac4ed Mon Sep 17 00:00:00 2001
From: Roberto Raggi <roberto.raggi@nokia.com>
Date: Mon, 5 Oct 2009 11:38:54 +0200
Subject: [PATCH] Improved template instantiation.

---
 src/libs/cplusplus/ResolveExpression.cpp   | 278 ++++++++++-----------
 src/libs/cplusplus/ResolveExpression.h     |  22 +-
 src/plugins/cpptools/cppcodecompletion.cpp |  20 +-
 3 files changed, 150 insertions(+), 170 deletions(-)

diff --git a/src/libs/cplusplus/ResolveExpression.cpp b/src/libs/cplusplus/ResolveExpression.cpp
index 31ff8a00865..23aa23a66d4 100644
--- a/src/libs/cplusplus/ResolveExpression.cpp
+++ b/src/libs/cplusplus/ResolveExpression.cpp
@@ -194,6 +194,22 @@ protected:
     { Q_ASSERT(false); }
 };
 
+template <typename _Tp>
+static QList<_Tp> removeDuplicates(const QList<_Tp> &results)
+{
+    QList<_Tp> uniqueList;
+    QSet<_Tp> processed;
+    foreach (const _Tp &r, results) {
+        if (processed.contains(r))
+            continue;
+
+        processed.insert(r);
+        uniqueList.append(r);
+    }
+
+    return uniqueList;
+}
+
 } // end of anonymous namespace
 
 /////////////////////////////////////////////////////////////////////
@@ -212,7 +228,7 @@ QList<ResolveExpression::Result> ResolveExpression::operator()(ExpressionAST *as
 {
     const QList<Result> previousResults = switchResults(QList<Result>());
     accept(ast);
-    return switchResults(previousResults);
+    return removeDuplicates(switchResults(previousResults));
 }
 
 QList<ResolveExpression::Result>
@@ -482,7 +498,7 @@ bool ResolveExpression::visit(QualifiedNameAST *ast)
             if (NamedType *namedTy = symbol->type()->asNamedType()) {
                 const Result r(namedTy, symbol);
                 const QList<Symbol *> resolvedClasses =
-                        resolveClass(r, _context);
+                        resolveClass(namedTy->name(), r, _context);
                 if (resolvedClasses.count()) {
                     foreach (Symbol *s, resolvedClasses) {
                         addResult(s->type(), s);
@@ -591,7 +607,7 @@ bool ResolveExpression::visit(ArrayAccessAST *ast)
             addResult(arrTy->elementType(), contextSymbol);
         } else if (NamedType *namedTy = ty->asNamedType()) {
             const QList<Symbol *> classObjectCandidates =
-                    symbolsForDotAcccess(p, _context);
+                    symbolsForDotAcccess(namedTy->name(), p, _context);
 
             foreach (Symbol *classObject, classObjectCandidates) {
                 const QList<Result> overloads =
@@ -630,30 +646,38 @@ bool ResolveExpression::visit(MemberAccessAST *ast)
     return false;
 }
 
-QList<Symbol *> ResolveExpression::resolveBaseExpression(const QList<Result> &baseResults, int accessOp) const
+QList<ResolveExpression::Result>
+ResolveExpression::resolveBaseExpression(const QList<Result> &baseResults, int accessOp) const
 {
-    QList<Symbol *> classObjectCandidates;
+    QList<Result> results;
 
     if (baseResults.isEmpty())
-        return classObjectCandidates;
+        return results;
 
     Result result = baseResults.first();
+    FullySpecifiedType ty = result.first.simplified();
+    Symbol *lastVisibleSymbol = result.second;
 
     if (accessOp == T_ARROW)  {
-        FullySpecifiedType ty = result.first.simplified();
+        if (lastVisibleSymbol && ty->isClassType() && ! lastVisibleSymbol->isClass()) {
+            // ### remove ! lastVisibleSymbol->isClass() from the condition.
+            results.append(Result(ty, lastVisibleSymbol));
 
-        if (Class *classTy = ty->asClassType()) {
-            Symbol *symbol = result.second;
-            if (symbol && ! symbol->isClass())
-                classObjectCandidates.append(classTy);
         } else if (NamedType *namedTy = ty->asNamedType()) {
             // ### This code is pretty slow.
             const QList<Symbol *> candidates = _context.resolve(namedTy->name());
+
             foreach (Symbol *candidate, candidates) {
                 if (candidate->isTypedef()) {
-                    ty = candidate->type();
-                    const ResolveExpression::Result r(ty, candidate);
+                    FullySpecifiedType declTy = candidate->type().simplified();
+                    const ResolveExpression::Result r(declTy, candidate);
+
+                    // update the result
                     result = r;
+
+                    // refresh the cached ty and lastVisibileSymbol.
+                    ty = result.first.simplified();
+                    lastVisibleSymbol = result.second;
                     break;
                 }
             }
@@ -662,82 +686,49 @@ QList<Symbol *> ResolveExpression::resolveBaseExpression(const QList<Result> &ba
         if (NamedType *namedTy = ty->asNamedType()) {
             ResolveClass resolveClass;
 
-            const QList<Symbol *> candidates = resolveClass(result, _context);
+            const QList<Symbol *> candidates = resolveClass(namedTy->name(), result, _context);
             foreach (Symbol *classObject, candidates) {
                 const QList<Result> overloads = resolveArrowOperator(result, namedTy,
                                                                      classObject->asClass());
 
-                foreach (Result r, overloads) {
-                    FullySpecifiedType ty = r.first;
-                    Function *funTy = ty->asFunctionType();
+                foreach (const Result &r, overloads) {
+                    FullySpecifiedType typeOfOverloadFunction = r.first.simplified();
+                    Symbol *lastVisibleSymbol = r.second;
+                    Function *funTy = typeOfOverloadFunction->asFunctionType();
                     if (! funTy)
                         continue;
 
-                    ty = funTy->returnType().simplified();
+                    typeOfOverloadFunction = funTy->returnType().simplified();
 
-                    if (PointerType *ptrTy = ty->asPointerType()) {
-                        if (NamedType *namedTy = ptrTy->elementType()->asNamedType()) {
-                            const QList<Symbol *> classes =
-                                    resolveClass(namedTy, result, _context);
+                    if (PointerType *ptrTy = typeOfOverloadFunction->asPointerType()) {
+                        FullySpecifiedType elementTy = ptrTy->elementType().simplified();
 
-                            foreach (Symbol *c, classes) {
-                                if (! classObjectCandidates.contains(c))
-                                    classObjectCandidates.append(c);
-                            }
-                        }
+                        if (elementTy->isNamedType())
+                            results.append(Result(elementTy, lastVisibleSymbol));
                     }
                 }
             }
         } else if (PointerType *ptrTy = ty->asPointerType()) {
-            if (NamedType *namedTy = ptrTy->elementType()->asNamedType()) {
-                ResolveClass resolveClass;
+            FullySpecifiedType elementTy = ptrTy->elementType().simplified();
 
-                const QList<Symbol *> classes = resolveClass(namedTy, result,
-                                                             _context);
-
-                foreach (Symbol *c, classes) {
-                    if (! classObjectCandidates.contains(c))
-                        classObjectCandidates.append(c);
-                }
-            } else if (Class *classTy = ptrTy->elementType()->asClassType()) {
-                // typedef struct { int x } *Ptr;
-                // Ptr p;
-                // p->
-                classObjectCandidates.append(classTy);
-            }
+            if (elementTy->isNamedType() || elementTy->isClassType())
+                results.append(Result(elementTy, lastVisibleSymbol));
         }
     } else if (accessOp == T_DOT) {
-        FullySpecifiedType ty = result.first.simplified();
-
-        NamedType *namedTy = 0;
-
-        if (Class *classTy = ty->asClassType()) {
-            Symbol *symbol = result.second;
-            if (symbol && ! symbol->isClass())
-                classObjectCandidates.append(classTy);
-        } else {
-            namedTy = ty->asNamedType();
-            if (! namedTy) {
-                Function *fun = ty->asFunctionType();
-                if (fun && fun->scope() && (fun->scope()->isBlockScope() || fun->scope()->isNamespaceScope()))
-                    namedTy = fun->returnType()->asNamedType();
-            }
-        }
+        if (ty->isClassType() || ty->isNamedType())
+            results.append(Result(ty, lastVisibleSymbol));
 
-        if (namedTy) {
-            ResolveClass resolveClass;
-            const QList<Symbol *> symbols = resolveClass(namedTy, result,
-                                                         _context);
-            foreach (Symbol *symbol, symbols) {
-                if (classObjectCandidates.contains(symbol))
-                    continue;
-                if (Class *klass = symbol->asClass())
-                    classObjectCandidates.append(klass);
+        if (Function *fun = ty->asFunctionType()) {
+            Scope *funScope = fun->scope();
+
+            if (funScope && (funScope->isBlockScope() || funScope->isNamespaceScope())) {
+                FullySpecifiedType retTy = fun->returnType().simplified();
+                results.append(Result(retTy, lastVisibleSymbol));
             }
         }
     }
 
-    return classObjectCandidates;
+    return removeDuplicates(results);
 }
 
 QList<ResolveExpression::Result>
@@ -745,25 +736,42 @@ ResolveExpression::resolveMemberExpression(const QList<Result> &baseResults,
                                            unsigned accessOp,
                                            Name *memberName) const
 {
+    ResolveClass resolveClass;
     QList<Result> results;
 
-    const QList<Symbol *> classObjectCandidates = resolveBaseExpression(baseResults, accessOp);
-    foreach (Symbol *candidate, classObjectCandidates) {
-        Class *klass = candidate->asClass();
-        if (! klass)
-            continue;
+    const QList<Result> classObjectResults = resolveBaseExpression(baseResults, accessOp);
+    foreach (const Result &r, classObjectResults) {
+        FullySpecifiedType ty = r.first;
+
+        if (Class *klass = ty->asClassType())
+            results += resolveMember(memberName, klass);
 
-        results += resolveMember(memberName, klass);
+        else if (NamedType *namedTy = ty->asNamedType()) {
+            Name *className = namedTy->name();
+            const QList<Symbol *> classes = resolveClass(className, r, _context);
+
+            foreach (Symbol *c, classes) {
+                if (Class *klass = c->asClass())
+                    results += resolveMember(memberName, klass, className);
+            }
+        }
     }
 
-    return results;
+    return removeDuplicates(results);
 }
 
 QList<ResolveExpression::Result>
-ResolveExpression::resolveMember(Name *memberName, Class *klass) const
+ResolveExpression::resolveMember(Name *memberName, Class *klass,
+                                 Name *className) const
 {
     QList<Result> results;
 
+    if (! className)
+        className = klass->name();
+
+    if (! className)
+        return results;
+
     QList<Scope *> scopes;
     _context.expand(klass->members(), _context.visibleScopes(), &scopes);
 
@@ -771,35 +779,30 @@ ResolveExpression::resolveMember(Name *memberName, Class *klass) const
 
     foreach (Symbol *candidate, candidates) {
         FullySpecifiedType ty = candidate->type();
-
-        if (Name *className = klass->name()) {
-            Name *unqualifiedNameId = className;
-
-            if (QualifiedNameId *q = className->asQualifiedNameId())
-                unqualifiedNameId = q->unqualifiedNameId();
-
-            if (TemplateNameId *templId = unqualifiedNameId->asTemplateNameId()) {
-                Substitution subst;
-
-                for (unsigned i = 0; i < templId->templateArgumentCount(); ++i) {
-                    FullySpecifiedType templArgTy = templId->templateArgumentAt(i);
-
-                    if (i < klass->templateParameterCount())
-                        subst.append(qMakePair(klass->templateParameterAt(i)->name(),
-                                               templArgTy));
-                }
-
-                Instantiation inst(control(), subst);
-                ty = inst(ty);
+        Name *unqualifiedNameId = className;
+        
+        if (QualifiedNameId *q = className->asQualifiedNameId())
+            unqualifiedNameId = q->unqualifiedNameId();
+        
+        if (TemplateNameId *templId = unqualifiedNameId->asTemplateNameId()) {
+            Substitution subst;
+            
+            for (unsigned i = 0; i < templId->templateArgumentCount(); ++i) {
+                FullySpecifiedType templArgTy = templId->templateArgumentAt(i);
+                
+                if (i < klass->templateParameterCount())
+                    subst.append(qMakePair(klass->templateParameterAt(i)->name(),
+                                           templArgTy));
             }
+            
+            Instantiation inst(control(), subst);
+            ty = inst(ty);
         }
-
-        const Result result(ty, candidate);
-        if (! results.contains(result))
-            results.append(result);
+        
+        results.append(Result(ty, candidate));
     }
 
-    return results;
+    return removeDuplicates(results);
 }
 
 QList<ResolveExpression::Result>
@@ -832,11 +835,10 @@ ResolveExpression::resolveArrowOperator(const Result &,
         }
 
         const Result result(ty, candidate);
-        if (! results.contains(result))
-            results.append(result);
+        results.append(result);
     }
 
-    return results;
+    return removeDuplicates(results);
 }
 
 QList<ResolveExpression::Result>
@@ -870,12 +872,10 @@ ResolveExpression::resolveArrayOperator(const Result &,
             ty = inst(ty);
         }
 
-        const Result result(ty, candidate);
-        if (! results.contains(result))
-            results.append(result);
+        results.append(Result(ty, candidate));
     }
 
-    return results;
+    return removeDuplicates(results);
 }
 
 bool ResolveExpression::visit(PostIncrDecrAST *)
@@ -894,27 +894,18 @@ bool ResolveClass::pointerAccess() const
 void ResolveClass::setPointerAccess(bool pointerAccess)
 { _pointerAccess = pointerAccess; }
 
-QList<Symbol *> ResolveClass::operator()(NamedType *namedTy,
-                                         ResolveExpression::Result p,
-                                         const LookupContext &context)
-{
-    const QList<ResolveExpression::Result> previousBlackList = _blackList;
-    const QList<Symbol *> symbols = resolveClass(namedTy, p, context);
-    _blackList = previousBlackList;
-    return symbols;
-}
-
-QList<Symbol *> ResolveClass::operator()(ResolveExpression::Result p,
+QList<Symbol *> ResolveClass::operator()(Name *name,
+                                         const ResolveExpression::Result &p,
                                          const LookupContext &context)
 {
     const QList<ResolveExpression::Result> previousBlackList = _blackList;
-    const QList<Symbol *> symbols = resolveClass(p, context);
+    const QList<Symbol *> symbols = resolveClass(name, p, context);
     _blackList = previousBlackList;
     return symbols;
 }
 
-QList<Symbol *> ResolveClass::resolveClass(NamedType *namedTy,
-                                           ResolveExpression::Result p,
+QList<Symbol *> ResolveClass::resolveClass(Name *name,
+                                           const ResolveExpression::Result &p,
                                            const LookupContext &context)
 {
     QList<Symbol *> resolvedSymbols;
@@ -925,7 +916,7 @@ QList<Symbol *> ResolveClass::resolveClass(NamedType *namedTy,
     _blackList.append(p);
 
     const QList<Symbol *> candidates =
-            context.resolve(namedTy->name(), context.visibleScopes(p));
+            context.resolve(name, context.visibleScopes(p));
 
     foreach (Symbol *candidate, candidates) {
         if (Class *klass = candidate->asClass()) {
@@ -936,10 +927,13 @@ QList<Symbol *> ResolveClass::resolveClass(NamedType *namedTy,
             if (Declaration *decl = candidate->asDeclaration()) {
                 if (_pointerAccess && decl->type()->isPointerType()) {
                     PointerType *ptrTy = decl->type()->asPointerType();
-                    _pointerAccess = false;
-                    const ResolveExpression::Result r(ptrTy->elementType(), decl);
-                    resolvedSymbols += resolveClass(r, context);
-                    _pointerAccess = true;
+                    FullySpecifiedType elementTy = ptrTy->elementType().simplified();
+                    if (NamedType *namedTy = elementTy->asNamedType()) {
+                        _pointerAccess = false;
+                        const ResolveExpression::Result r(elementTy, decl);
+                        resolvedSymbols += resolveClass(namedTy->name(), r, context);
+                        _pointerAccess = true;
+                    }
                 } else if (Class *asClass = decl->type()->asClassType()) {
                     // typedef struct { } Point;
                     // Point pt;
@@ -949,8 +943,11 @@ QList<Symbol *> ResolveClass::resolveClass(NamedType *namedTy,
                     // typedef Point Boh;
                     // Boh b;
                     // b.
-                    const ResolveExpression::Result r(decl->type(), decl);
-                    resolvedSymbols += resolveClass(r, context);
+                    FullySpecifiedType declType = decl->type().simplified();
+                    if (NamedType *namedTy = declType->asNamedType()) {
+                        const ResolveExpression::Result r(declType, decl);
+                        resolvedSymbols += resolveClass(namedTy->name(), r, context);
+                    }
                 }
             }
         } else if (Declaration *decl = candidate->asDeclaration()) {
@@ -958,8 +955,11 @@ QList<Symbol *> ResolveClass::resolveClass(NamedType *namedTy,
                 // QString foo("ciao");
                 // foo.
                 if (funTy->scope() && (funTy->scope()->isBlockScope() || funTy->scope()->isNamespaceScope())) {
-                    const ResolveExpression::Result r(funTy->returnType(), decl);
-                    resolvedSymbols += resolveClass(r, context);
+                    FullySpecifiedType retTy = funTy->returnType().simplified();
+                    if (NamedType *namedTy = retTy->asNamedType()) {
+                        const ResolveExpression::Result r(retTy, decl);
+                        resolvedSymbols += resolveClass(namedTy->name(), r, context);
+                    }
                 }
             }
         }
@@ -967,19 +967,3 @@ QList<Symbol *> ResolveClass::resolveClass(NamedType *namedTy,
 
     return resolvedSymbols;
 }
-
-QList<Symbol *> ResolveClass::resolveClass(ResolveExpression::Result p,
-                                           const LookupContext &context)
-{
-    FullySpecifiedType ty = p.first;
-
-    if (NamedType *namedTy = ty->asNamedType()) {
-        return resolveClass(namedTy, p, context);
-    } else if (ReferenceType *refTy = ty->asReferenceType()) {
-        const ResolveExpression::Result e(refTy->elementType(), p.second);
-        return resolveClass(e, context);
-    }
-
-    return QList<Symbol *>();
-}
-
diff --git a/src/libs/cplusplus/ResolveExpression.h b/src/libs/cplusplus/ResolveExpression.h
index 71289ef3432..fb00f9e23f6 100644
--- a/src/libs/cplusplus/ResolveExpression.h
+++ b/src/libs/cplusplus/ResolveExpression.h
@@ -53,7 +53,7 @@ public:
                                           unsigned accessOp,
                                           Name *memberName) const;
 
-    QList<Result> resolveMember(Name *memberName, Class *klass) const;
+    QList<Result> resolveMember(Name *memberName, Class *klass, Name *className = 0) const;
 
     QList<Result> resolveArrowOperator(const Result &result,
                                        NamedType *namedTy,
@@ -64,8 +64,8 @@ public:
                                        Class *klass) const;
 
 
-    QList<Symbol *> resolveBaseExpression(const QList<Result> &baseResults,
-                                          int accessOp) const;
+    QList<Result> resolveBaseExpression(const QList<Result> &baseResults,
+                                        int accessOp) const;
 
 protected:
     QList<Result> switchResults(const QList<Result> &symbols);
@@ -131,20 +131,14 @@ public:
     bool pointerAccess() const;
     void setPointerAccess(bool pointerAccess);
 
-    QList<Symbol *> operator()(NamedType *namedTy,
-                               ResolveExpression::Result p,
-                               const LookupContext &context);
-
-    QList<Symbol *> operator()(ResolveExpression::Result p,
+    QList<Symbol *> operator()(Name *name,
+                               const ResolveExpression::Result &p,
                                const LookupContext &context);
 
 private:
-    QList<Symbol *> resolveClass(NamedType *namedTy,
-                                        ResolveExpression::Result p,
-                                        const LookupContext &context);
-
-    QList<Symbol *> resolveClass(ResolveExpression::Result p,
-                                        const LookupContext &context);
+    QList<Symbol *> resolveClass(Name *name,
+                                 const ResolveExpression::Result &p,
+                                 const LookupContext &context);
 
 private:
     QList<ResolveExpression::Result> _blackList;
diff --git a/src/plugins/cpptools/cppcodecompletion.cpp b/src/plugins/cpptools/cppcodecompletion.cpp
index 988bba99665..cd0c8f705ed 100644
--- a/src/plugins/cpptools/cppcodecompletion.cpp
+++ b/src/plugins/cpptools/cppcodecompletion.cpp
@@ -1011,7 +1011,7 @@ bool CppCodeCompletion::completeMember(const QList<TypeOfExpression::Result> &re
             ResolveExpression resolveExpression(context);
             ResolveClass resolveClass;
 
-            const QList<Symbol *> candidates = resolveClass(result, context);
+            const QList<Symbol *> candidates = resolveClass(namedTy->name(), result, context);
             foreach (Symbol *classObject, candidates) {
                 const QList<TypeOfExpression::Result> overloads =
                         resolveExpression.resolveArrowOperator(result, namedTy,
@@ -1026,9 +1026,10 @@ bool CppCodeCompletion::completeMember(const QList<TypeOfExpression::Result> &re
                     ty = funTy->returnType().simplified();
 
                     if (PointerType *ptrTy = ty->asPointerType()) {
-                        if (NamedType *namedTy = ptrTy->elementType()->asNamedType()) {
+                        FullySpecifiedType elementTy = ptrTy->elementType().simplified();
+                        if (NamedType *namedTy = elementTy->asNamedType()) {
                             const QList<Symbol *> classes =
-                                    resolveClass(namedTy, result, context);
+                                    resolveClass(namedTy->name(), result, context);
 
                             foreach (Symbol *c, classes) {
                                 if (! classObjectCandidates.contains(c))
@@ -1039,17 +1040,18 @@ bool CppCodeCompletion::completeMember(const QList<TypeOfExpression::Result> &re
                 }
             }
         } else if (PointerType *ptrTy = ty->asPointerType()) {
-            if (NamedType *namedTy = ptrTy->elementType()->asNamedType()) {
+            FullySpecifiedType elementTy = ptrTy->elementType().simplified();
+            if (NamedType *namedTy = elementTy->asNamedType()) {
                 ResolveClass resolveClass;
 
-                const QList<Symbol *> classes = resolveClass(namedTy, result,
+                const QList<Symbol *> classes = resolveClass(namedTy->name(), result,
                                                              context);
 
                 foreach (Symbol *c, classes) {
                     if (! classObjectCandidates.contains(c))
                         classObjectCandidates.append(c);
                 }
-            } else if (Class *classTy = ptrTy->elementType()->asClassType()) {
+            } else if (Class *classTy = elementTy->asClassType()) {
                 // typedef struct { int x } *Ptr;
                 // Ptr p;
                 // p->
@@ -1099,7 +1101,7 @@ bool CppCodeCompletion::completeMember(const QList<TypeOfExpression::Result> &re
 
         if (namedTy) {
             ResolveClass resolveClass;
-            const QList<Symbol *> symbols = resolveClass(namedTy, result,
+            const QList<Symbol *> symbols = resolveClass(namedTy->name(), result,
                                                          context);
             foreach (Symbol *symbol, symbols) {
                 if (classObjectCandidates.contains(symbol))
@@ -1330,7 +1332,7 @@ bool CppCodeCompletion::completeQtMethod(const QList<TypeOfExpression::Result> &
         FullySpecifiedType ty = p.first.simplified();
 
         if (PointerType *ptrTy = ty->asPointerType())
-            ty = ptrTy->elementType();
+            ty = ptrTy->elementType().simplified();
         else
             continue; // not a pointer or a reference to a pointer.
 
@@ -1339,7 +1341,7 @@ bool CppCodeCompletion::completeQtMethod(const QList<TypeOfExpression::Result> &
             continue;
 
         const QList<Symbol *> classObjects =
-                resolveClass(namedTy, p, context);
+                resolveClass(namedTy->name(), p, context);
 
         if (classObjects.isEmpty())
             continue;
-- 
GitLab