From 66a9ef072535d33b8876ebc873134fac2d6c7e02 Mon Sep 17 00:00:00 2001
From: Roberto Raggi <roberto.raggi@nokia.com>
Date: Wed, 5 May 2010 10:59:46 +0200
Subject: [PATCH] Ported completeScope(), completeNamespace() and
 completeClass() to use the new LookupContext.

---
 src/libs/cplusplus/LookupContext.cpp       |  10 ++
 src/libs/cplusplus/LookupContext.h         |   1 +
 src/plugins/cpptools/cppcodecompletion.cpp | 169 +++++++++++++++------
 src/plugins/cpptools/cppcodecompletion.h   |  14 ++
 4 files changed, 151 insertions(+), 43 deletions(-)

diff --git a/src/libs/cplusplus/LookupContext.cpp b/src/libs/cplusplus/LookupContext.cpp
index ccb36e9cbb9..36fd3de8df6 100644
--- a/src/libs/cplusplus/LookupContext.cpp
+++ b/src/libs/cplusplus/LookupContext.cpp
@@ -138,6 +138,16 @@ ClassOrNamespace *LookupContext::classOrNamespace(Symbol *symbol) const
     return bindings()->findClassOrNamespace(symbol);
 }
 
+ClassOrNamespace *LookupContext::classOrNamespace(const Name *name, Symbol *lastVisibleSymbol) const
+{
+    Scope *scope = _thisDocument->globalSymbols();
+
+    if (lastVisibleSymbol && lastVisibleSymbol->scope())
+        scope = lastVisibleSymbol->scope();
+
+    return classOrNamespace(name, lastVisibleSymbol);
+}
+
 QList<Symbol *> LookupContext::lookup(const Name *name, Scope *scope) const
 {
     QList<Symbol *> candidates;
diff --git a/src/libs/cplusplus/LookupContext.h b/src/libs/cplusplus/LookupContext.h
index a39e7bb7371..ad8f43f2682 100644
--- a/src/libs/cplusplus/LookupContext.h
+++ b/src/libs/cplusplus/LookupContext.h
@@ -178,6 +178,7 @@ public:
 
     ClassOrNamespace *globalNamespace() const;
 
+    ClassOrNamespace *classOrNamespace(const Name *name, Symbol *lastVisibleSymbol) const;
     ClassOrNamespace *classOrNamespace(const Name *name, Scope *scope) const;
     ClassOrNamespace *classOrNamespace(Symbol *symbol) const;
 
diff --git a/src/plugins/cpptools/cppcodecompletion.cpp b/src/plugins/cpptools/cppcodecompletion.cpp
index 519dd69ed51..a5f583254cd 100644
--- a/src/plugins/cpptools/cppcodecompletion.cpp
+++ b/src/plugins/cpptools/cppcodecompletion.cpp
@@ -52,6 +52,7 @@
 #include <cplusplus/ExpressionUnderCursor.h>
 #include <cplusplus/BackwardsScanner.h>
 #include <cplusplus/TokenUnderCursor.h>
+#include <cplusplus/LookupContext.h>
 
 #include <coreplugin/icore.h>
 #include <coreplugin/mimedatabase.h>
@@ -1149,25 +1150,41 @@ bool CppCodeCompletion::completeMember(const QList<LookupItem> &baseResults,
 }
 
 bool CppCodeCompletion::completeScope(const QList<LookupItem> &results,
-                                      const DeprecatedLookupContext &context)
+                                      const DeprecatedLookupContext &deprecatedContext)
 {
-    QList<Symbol *> classes, namespaces;
+    qDebug() << Q_FUNC_INFO;
+
+    if (results.isEmpty())
+        return false;
+
+    LookupContext context(deprecatedContext.expressionDocument(),
+                          deprecatedContext.thisDocument(),
+                          deprecatedContext.snapshot());
 
     foreach (const LookupItem &result, results) {
         FullySpecifiedType ty = result.type();
+        Symbol *lastVisibleSymbol = result.lastVisibleSymbol();
 
-        if (Class *classTy = ty->asClassType())
-            classes.append(classTy);
+        if (NamedType *namedTy = ty->asNamedType()) {
+            if (ClassOrNamespace *b = context.classOrNamespace(namedTy->name(), lastVisibleSymbol)) {
+                completeClass(b, context);
+                break;
+            }
 
-        else if (Namespace *namespaceTy = ty->asNamespaceType())
-            namespaces.append(namespaceTy);
-    }
+        } else if (Class *classTy = ty->asClassType()) {
+            if (ClassOrNamespace *b = context.classOrNamespace(classTy)) {
+                completeClass(b, context);
+                break;
+            }
 
-    if (! classes.isEmpty())
-        completeClass(classes, context);
+        } else if (Namespace *nsTy = ty->asNamespaceType()) {
+            if (ClassOrNamespace *b = context.classOrNamespace(nsTy)) {
+                completeNamespace(b, context);
+                break;
+            }
 
-    else if (! namespaces.isEmpty() && m_completions.isEmpty())
-        completeNamespace(namespaces, context);
+        }
+    }
 
     return ! m_completions.isEmpty();
 }
@@ -1295,61 +1312,127 @@ bool CppCodeCompletion::completeInclude(const QTextCursor &cursor)
     return !m_completions.isEmpty();
 }
 
-void CppCodeCompletion::completeNamespace(const QList<Symbol *> &candidates,
-                                          const DeprecatedLookupContext &context)
+void CppCodeCompletion::completeNamespace(ClassOrNamespace *b, const LookupContext &)
 {
-    QList<Scope *> todo;
-    QList<Scope *> visibleScopes = context.visibleScopes();
-    foreach (Symbol *candidate, candidates) {
-        if (Namespace *ns = candidate->asNamespace())
-            context.expand(ns->members(), visibleScopes, &todo);
-    }
+    QSet<ClassOrNamespace *> bindingsVisited;
+    QList<ClassOrNamespace *> bindingsToVisit;
+    bindingsToVisit.append(b);
 
-    foreach (Scope *scope, todo) {
-        if (! (scope->isNamespaceScope() || scope->isEnumScope()))
+    while (! bindingsToVisit.isEmpty()) {
+        ClassOrNamespace *binding = bindingsToVisit.takeFirst();
+        if (! binding || bindingsVisited.contains(binding))
             continue;
 
-        addCompletionItem(scope->owner());
+        bindingsVisited.insert(binding);
+        bindingsToVisit += binding->usings();
 
-        for (unsigned i = 0; i < scope->symbolCount(); ++i) {
-            addCompletionItem(scope->symbolAt(i));
+        QList<Scope *> scopesToVisit;
+        QSet<Scope *> scopesVisited;
+
+        foreach (Symbol *bb, binding->symbols()) {
+            if (Namespace *ns = bb->asNamespace())
+                scopesToVisit.append(ns->members());
+        }
+
+        foreach (Enum *e, binding->enums()) {
+            scopesToVisit.append(e->members());
+        }
+
+        while (! scopesToVisit.isEmpty()) {
+            Scope *scope = scopesToVisit.takeFirst();
+            if (! scope || scopesVisited.contains(scope))
+                continue;
+
+            scopesVisited.insert(scope);
+
+            for (Scope::iterator it = scope->firstSymbol(); it != scope->lastSymbol(); ++it) {
+                Symbol *member = *it;
+                addCompletionItem(member);
+            }
         }
     }
 }
 
-void CppCodeCompletion::completeClass(const QList<Symbol *> &candidates,
-                                      const DeprecatedLookupContext &context,
-                                      bool staticLookup)
+void CppCodeCompletion::completeNamespace(const QList<Symbol *> &candidates,
+                                          const DeprecatedLookupContext &deprecatedContext)
 {
     if (candidates.isEmpty())
         return;
 
-    Class *klass = candidates.first()->asClass();
+    else if (Namespace *ns = candidates.first()->asNamespace()) {
+        LookupContext context(deprecatedContext.expressionDocument(),
+                              deprecatedContext.thisDocument(),
+                              deprecatedContext.snapshot());
 
-    QList<Scope *> todo;
-    context.expand(klass->members(), context.visibleScopes(), &todo);
+        if (ClassOrNamespace *binding = context.classOrNamespace(ns))
+            completeNamespace(binding, context);
+    }
+}
 
-    foreach (Scope *scope, todo) {
-        if (! (scope->isClassScope() || scope->isEnumScope()))
+void CppCodeCompletion::completeClass(ClassOrNamespace *b, const LookupContext &, bool staticLookup)
+{
+    QSet<ClassOrNamespace *> bindingsVisited;
+    QList<ClassOrNamespace *> bindingsToVisit;
+    bindingsToVisit.append(b);
+
+    while (! bindingsToVisit.isEmpty()) {
+        ClassOrNamespace *binding = bindingsToVisit.takeFirst();
+        if (! binding || bindingsVisited.contains(binding))
             continue;
 
-        addCompletionItem(scope->owner());
+        bindingsVisited.insert(binding);
+        bindingsToVisit += binding->usings();
 
-        for (unsigned i = 0; i < scope->symbolCount(); ++i) {
-            Symbol *symbol = scope->symbolAt(i);
+        QList<Scope *> scopesToVisit;
+        QSet<Scope *> scopesVisited;
 
-            if (symbol->type().isFriend())
-                continue;
-            else if (! staticLookup && (symbol->isTypedef() ||
-                                        symbol->isEnum()    ||
-                                        symbol->isClass()))
+        foreach (Symbol *bb, binding->symbols()) {
+            if (Class *k = bb->asClass())
+                scopesToVisit.append(k->members());
+        }
+
+        foreach (Enum *e, binding->enums())
+            scopesToVisit.append(e->members());
+
+        while (! scopesToVisit.isEmpty()) {
+            Scope *scope = scopesToVisit.takeFirst();
+            if (! scope || scopesVisited.contains(scope))
                 continue;
 
-            addCompletionItem(symbol);
+            scopesVisited.insert(scope);
+
+            for (Scope::iterator it = scope->firstSymbol(); it != scope->lastSymbol(); ++it) {
+                Symbol *member = *it;
+                if (member->isFriend())
+                    continue;
+                else if (! staticLookup && (member->isTypedef() ||
+                                            member->isEnum()    ||
+                                            member->isClass()))
+                    continue;
+
+                addCompletionItem(member);
+            }
         }
     }
 }
 
+void CppCodeCompletion::completeClass(const QList<Symbol *> &candidates,
+                                      const DeprecatedLookupContext &deprecatedContext,
+                                      bool staticLookup)
+{
+    if (candidates.isEmpty())
+        return;
+
+    else if (Symbol *klass = candidates.first()) {
+        LookupContext context(deprecatedContext.expressionDocument(),
+                              deprecatedContext.thisDocument(),
+                              deprecatedContext.snapshot());
+
+        if (ClassOrNamespace *binding = context.classOrNamespace(klass))
+            completeClass(binding, context, staticLookup);
+    }
+}
+
 bool CppCodeCompletion::completeQtMethod(const QList<LookupItem> &results,
                                          const DeprecatedLookupContext &context,
                                          bool wantSignals)
@@ -1550,8 +1633,8 @@ void CppCodeCompletion::complete(const TextEditor::CompletionItem &item)
                         extraChars += QLatin1Char('<');
                     }
                 } else if (! function->isAmbiguous()) {
-		    if (m_spaceAfterFunctionName)
-			extraChars += QLatin1Char(' ');
+                    if (m_spaceAfterFunctionName)
+                        extraChars += QLatin1Char(' ');
                     extraChars += QLatin1Char('(');
 
                     // If the function doesn't return anything, automatically place the semicolon,
diff --git a/src/plugins/cpptools/cppcodecompletion.h b/src/plugins/cpptools/cppcodecompletion.h
index e7d171f6dc9..76090459c53 100644
--- a/src/plugins/cpptools/cppcodecompletion.h
+++ b/src/plugins/cpptools/cppcodecompletion.h
@@ -50,6 +50,13 @@ class ITextEditor;
 class BaseTextEditor;
 }
 
+namespace CPlusPlus {
+class LookupItem;
+class LookupContext;
+class DeprecatedLookupContext;
+class ClassOrNamespace;
+}
+
 namespace CppTools {
 namespace Internal {
 
@@ -116,9 +123,16 @@ private:
     bool completeScope(const QList<CPlusPlus::LookupItem> &,
                        const CPlusPlus::DeprecatedLookupContext &context);
 
+    void completeNamespace(CPlusPlus::ClassOrNamespace *binding,
+                           const CPlusPlus::LookupContext &context);
+
     void completeNamespace(const QList<CPlusPlus::Symbol *> &candidates,
                            const CPlusPlus::DeprecatedLookupContext &context);
 
+    void completeClass(CPlusPlus::ClassOrNamespace *b,
+                       const CPlusPlus::LookupContext &context,
+                       bool staticLookup = true);
+
     void completeClass(const QList<CPlusPlus::Symbol *> &candidates,
                        const CPlusPlus::DeprecatedLookupContext &context,
                        bool staticLookup = true);
-- 
GitLab