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