diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-09-21 16:56:56 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-09-21 16:56:56 +0000 |
commit | 86d9a52c24d390631a888d4ff812e1b15445e0a0 (patch) | |
tree | 1f30ab2df64a31faf773231cf5ac963cb118b134 | |
parent | 657f21bee4750eb28dfb4d60662919417a53d724 (diff) |
Refactor and simplify the CodeCompleteConsumer, so that all of the
real work is performed within Sema. Addresses Chris's comments, but
still retains the heavyweight list-of-multimaps data structure.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@82459 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/Sema/CodeCompleteConsumer.h | 210 | ||||
-rw-r--r-- | lib/Lex/Lexer.cpp | 25 | ||||
-rw-r--r-- | lib/Sema/CodeCompleteConsumer.cpp | 851 | ||||
-rw-r--r-- | lib/Sema/ParseAST.cpp | 4 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 5 | ||||
-rw-r--r-- | lib/Sema/SemaCodeComplete.cpp | 929 |
6 files changed, 945 insertions, 1079 deletions
diff --git a/include/clang/Sema/CodeCompleteConsumer.h b/include/clang/Sema/CodeCompleteConsumer.h index a8facd8fdc..3a7e73706b 100644 --- a/include/clang/Sema/CodeCompleteConsumer.h +++ b/include/clang/Sema/CodeCompleteConsumer.h @@ -13,15 +13,9 @@ #ifndef LLVM_CLANG_SEMA_CODECOMPLETECONSUMER_H #define LLVM_CLANG_SEMA_CODECOMPLETECONSUMER_H -#include "clang/AST/DeclarationName.h" -#include "clang/AST/Type.h" -#include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" -#include <list> -#include <map> #include <memory> #include <string> -#include <vector> namespace llvm { class raw_ostream; @@ -29,10 +23,7 @@ class raw_ostream; namespace clang { -class Decl; -class DeclContext; class NamedDecl; -class Scope; class Sema; /// \brief A "string" used to describe how code completion can @@ -90,8 +81,8 @@ public: /// \brief Create a new placeholder chunk. static Chunk CreatePlaceholder(const char *Placeholder); - - /// \brief Destroy this chunk. + + /// \brief Destroy this chunk, deallocating any memory it owns. void Destroy(); }; @@ -135,10 +126,6 @@ public: /// \brief Abstract interface for a consumer of code-completion /// information. class CodeCompleteConsumer { - /// \brief The semantic-analysis object to which this code-completion - /// consumer is attached. - Sema &SemaRef; - public: /// \brief Captures a result of code completion. struct Result { @@ -176,209 +163,38 @@ public: /// \brief Build a result that refers to a keyword or symbol. Result(const char *Keyword, unsigned Rank) : Kind(RK_Keyword), Keyword(Keyword), Rank(Rank), Hidden(false) { } - }; - - /// \brief A container of code-completion results. - class ResultSet { - public: - /// \brief The type of a name-lookup filter, which can be provided to the - /// name-lookup routines to specify which declarations should be included in - /// the result set (when it returns true) and which declarations should be - /// filtered out (returns false). - typedef bool (CodeCompleteConsumer::*LookupFilter)(NamedDecl *) const; - - private: - /// \brief The actual results we have found. - std::vector<Result> Results; - - /// \brief A record of all of the declarations we have found and placed - /// into the result set, used to ensure that no declaration ever gets into - /// the result set twice. - llvm::SmallPtrSet<Decl*, 16> AllDeclsFound; - - /// \brief A mapping from declaration names to the declarations that have - /// this name within a particular scope and their index within the list of - /// results. - typedef std::multimap<DeclarationName, - std::pair<NamedDecl *, unsigned> > ShadowMap; - - /// \brief The code-completion consumer that is producing these results. - CodeCompleteConsumer &Completer; - /// \brief If non-NULL, a filter function used to remove any code-completion - /// results that are not desirable. - LookupFilter Filter; - - /// \brief A list of shadow maps, which is used to model name hiding at - /// different levels of, e.g., the inheritance hierarchy. - std::list<ShadowMap> ShadowMaps; - - public: - explicit ResultSet(CodeCompleteConsumer &Completer, - LookupFilter Filter = 0) - : Completer(Completer), Filter(Filter) { } - - /// \brief Set the filter used for code-completion results. - void setFilter(LookupFilter Filter) { - this->Filter = Filter; - } - - typedef std::vector<Result>::iterator iterator; - iterator begin() { return Results.begin(); } - iterator end() { return Results.end(); } - - Result *data() { return Results.empty()? 0 : &Results.front(); } - unsigned size() const { return Results.size(); } - bool empty() const { return Results.empty(); } - - /// \brief Add a new result to this result set (if it isn't already in one - /// of the shadow maps), or replace an existing result (for, e.g., a - /// redeclaration). - void MaybeAddResult(Result R); - - /// \brief Enter into a new scope. - void EnterNewScope(); - - /// \brief Exit from the current scope. - void ExitScope(); + /// \brief Create a new code-completion string that describes how to insert + /// this result into a program. + CodeCompletionString *CreateCodeCompletionString(Sema &S); }; - - /// \brief Create a new code-completion consumer and registers it with - /// the given semantic-analysis object. - explicit CodeCompleteConsumer(Sema &S); - + /// \brief Deregisters and destroys this code-completion consumer. virtual ~CodeCompleteConsumer(); - - /// \brief Retrieve the semantic-analysis object to which this code-completion - /// consumer is attached. - Sema &getSema() const { return SemaRef; } - + /// \name Code-completion callbacks //@{ - /// \brief Process the finalized code-completion results. virtual void ProcessCodeCompleteResults(Result *Results, unsigned NumResults) { } - - /// \brief Code completion for a member access expression, e.g., "x->" or - /// "x.". - /// - /// \param S is the scope in which code-completion occurs. - /// - /// \param BaseType is the type whose members are being accessed. - /// - /// \param IsArrow whether this member referenced was written with an - /// arrow ("->") or a period ("."). - virtual void CodeCompleteMemberReferenceExpr(Scope *S, QualType BaseType, - bool IsArrow); - - /// \brief Code completion for a tag name following an enum, class, struct, - /// or union keyword. - virtual void CodeCompleteTag(Scope *S, ElaboratedType::TagKind TK); - - /// \brief Code completion for a qualified-id, e.g., "std::" - /// - /// \param S the scope in which the nested-name-specifier occurs. - /// - /// \param NNS the nested-name-specifier before the code-completion location. - /// - /// \param EnteringContext whether the parser will be entering the scope of - /// the qualified-id. - virtual void CodeCompleteQualifiedId(Scope *S, NestedNameSpecifier *NNS, - bool EnteringContext); - - /// \brief Code completion for a C++ "using" declaration or directive. - /// - /// This code completion action is invoked when the code-completion token is - /// found after the "using" keyword. - /// - /// \param S the scope in which the "using" occurs. - virtual void CodeCompleteUsing(Scope *S); - - /// \brief Code completion for a C++ using directive. - /// - /// This code completion action is invoked when the code-completion token is - /// found after "using namespace". - /// - /// \param S the scope in which the "using namespace" occurs. - virtual void CodeCompleteUsingDirective(Scope *S); - - /// \brief Code completion for a C++ namespace declaration or namespace - /// alias declaration. - /// - /// This code completion action is invoked when the code-completion token is - /// found after "namespace". - /// - /// \param S the scope in which the "namespace" token occurs. - virtual void CodeCompleteNamespaceDecl(Scope *S); - - /// \brief Code completion for a C++ namespace alias declaration. - /// - /// This code completion action is invoked when the code-completion token is - /// found after "namespace identifier = ". - /// - /// \param S the scope in which the namespace alias declaration occurs. - virtual void CodeCompleteNamespaceAliasDecl(Scope *S); - - /// \brief Code completion for an operator name. - /// - /// This code completion action is invoked when the code-completion token is - /// found after the keyword "operator". - /// - /// \param S the scope in which the operator keyword occurs. - virtual void CodeCompleteOperatorName(Scope *S); - //@} - - /// \name Name lookup functions - /// - /// The name lookup functions in this group collect code-completion results - /// by performing a form of name looking into a scope or declaration context. - //@{ - unsigned CollectLookupResults(Scope *S, unsigned InitialRank, - ResultSet &Results); - unsigned CollectMemberLookupResults(DeclContext *Ctx, unsigned InitialRank, - ResultSet &Results); - unsigned CollectMemberLookupResults(DeclContext *Ctx, unsigned InitialRank, - llvm::SmallPtrSet<DeclContext *, 16> &Visited, - ResultSet &Results); - //@} - - /// \name Name lookup predicates - /// - /// These predicates can be passed to the name lookup functions to filter the - /// results of name lookup. All of the predicates have the same type, so that - /// - //@{ - bool IsNestedNameSpecifier(NamedDecl *ND) const; - bool IsEnum(NamedDecl *ND) const; - bool IsClassOrStruct(NamedDecl *ND) const; - bool IsUnion(NamedDecl *ND) const; - bool IsNamespace(NamedDecl *ND) const; - bool IsNamespaceOrAlias(NamedDecl *ND) const; - bool IsType(NamedDecl *ND) const; - //@} - - /// \name Utility functions - /// - //@{ - bool canHiddenResultBeFound(NamedDecl *Hidden, NamedDecl *Visible); - void AddTypeSpecifierResults(unsigned Rank, ResultSet &Results); - CodeCompletionString *CreateCodeCompletionString(Result R); //@} }; /// \brief A simple code-completion consumer that prints the results it /// receives in a simple format. class PrintingCodeCompleteConsumer : public CodeCompleteConsumer { + /// \brief The semantic-analysis object to which this code-completion + /// consumer is attached. + Sema &SemaRef; + /// \brief The raw output stream. llvm::raw_ostream &OS; - + public: /// \brief Create a new printing code-completion consumer that prints its /// results to the given raw output stream. PrintingCodeCompleteConsumer(Sema &S, llvm::raw_ostream &OS) - : CodeCompleteConsumer(S), OS(OS) { } + : SemaRef(S), OS(OS) { } /// \brief Prints the finalized code-completion results. virtual void ProcessCodeCompleteResults(Result *Results, diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp index 351b63f6bb..74ac55cf2e 100644 --- a/lib/Lex/Lexer.cpp +++ b/lib/Lex/Lexer.cpp @@ -1309,6 +1309,18 @@ bool Lexer::LexEndOfFile(Token &Result, const char *CurPtr) { SetCommentRetentionState(PP->getCommentRetentionState()); return true; // Have a token. } + + // If we are in raw mode, return this event as an EOF token. Let the caller + // that put us in raw mode handle the event. + if (isLexingRawMode()) { + Result.startToken(); + BufferPtr = BufferEnd; + FormTokenWithChars(Result, BufferEnd, tok::eof); + return true; + } + + // Otherwise, check if we are code-completing, then issue diagnostics for + // unterminated #if and missing newline. if (IsEofCodeCompletion) { // We're at the end of the file, but we've been asked to conside the @@ -1316,23 +1328,12 @@ bool Lexer::LexEndOfFile(Token &Result, const char *CurPtr) { // code-completion token. Result.startToken(); FormTokenWithChars(Result, CurPtr, tok::code_completion); - + // Only do the eof -> code_completion translation once. IsEofCodeCompletion = false; return true; } - // If we are in raw mode, return this event as an EOF token. Let the caller - // that put us in raw mode handle the event. - if (isLexingRawMode()) { - Result.startToken(); - BufferPtr = BufferEnd; - FormTokenWithChars(Result, BufferEnd, tok::eof); - return true; - } - - // Otherwise, issue diagnostics for unterminated #if and missing newline. - // If we are in a #if directive, emit an error. while (!ConditionalStack.empty()) { PP->Diag(ConditionalStack.back().IfLoc, diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp index 2e3d5cd88e..1e505090fb 100644 --- a/lib/Sema/CodeCompleteConsumer.cpp +++ b/lib/Sema/CodeCompleteConsumer.cpp @@ -1,4 +1,4 @@ -//===---- CodeCompleteConsumer.h - Code Completion Interface ----*- C++ -*-===// +//===--- CodeCompleteConsumer.cpp - Code Completion Interface ---*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -88,853 +88,11 @@ std::string CodeCompletionString::getAsString() const { // Code completion consumer implementation //===----------------------------------------------------------------------===// -CodeCompleteConsumer::CodeCompleteConsumer(Sema &S) : SemaRef(S) { - SemaRef.setCodeCompleteConsumer(this); -} - -CodeCompleteConsumer::~CodeCompleteConsumer() { - SemaRef.setCodeCompleteConsumer(0); -} - -void -CodeCompleteConsumer::CodeCompleteMemberReferenceExpr(Scope *S, - QualType BaseType, - bool IsArrow) { - if (IsArrow) { - if (const PointerType *Ptr = BaseType->getAs<PointerType>()) - BaseType = Ptr->getPointeeType(); - else if (BaseType->isObjCObjectPointerType()) - /*Do nothing*/ ; - else - return; - } - - ResultSet Results(*this); - unsigned NextRank = 0; - - if (const RecordType *Record = BaseType->getAs<RecordType>()) { - NextRank = CollectMemberLookupResults(Record->getDecl(), NextRank, Results); - - if (getSema().getLangOptions().CPlusPlus) { - if (!Results.empty()) { - // The "template" keyword can follow "->" or "." in the grammar. - // However, we only want to suggest the template keyword if something - // is dependent. - bool IsDependent = BaseType->isDependentType(); - if (!IsDependent) { - for (Scope *DepScope = S; DepScope; DepScope = DepScope->getParent()) - if (DeclContext *Ctx = (DeclContext *)DepScope->getEntity()) { - IsDependent = Ctx->isDependentContext(); - break; - } - } - - if (IsDependent) - Results.MaybeAddResult(Result("template", NextRank++)); - } - - // We could have the start of a nested-name-specifier. Add those - // results as well. - Results.setFilter(&CodeCompleteConsumer::IsNestedNameSpecifier); - CollectLookupResults(S, NextRank, Results); - } - - // Hand off the results found for code completion. - ProcessCodeCompleteResults(Results.data(), Results.size()); - - // We're done! - return; - } -} - -void CodeCompleteConsumer::CodeCompleteTag(Scope *S, ElaboratedType::TagKind TK) { - ResultSet::LookupFilter Filter = 0; - switch (TK) { - case ElaboratedType::TK_enum: - Filter = &CodeCompleteConsumer::IsEnum; - break; - - case ElaboratedType::TK_class: - case ElaboratedType::TK_struct: - Filter = &CodeCompleteConsumer::IsClassOrStruct; - break; - - case ElaboratedType::TK_union: - Filter = &CodeCompleteConsumer::IsUnion; - break; - } - - ResultSet Results(*this, Filter); - unsigned NextRank = CollectLookupResults(S, 0, Results); - - if (getSema().getLangOptions().CPlusPlus) { - // We could have the start of a nested-name-specifier. Add those - // results as well. - Results.setFilter(&CodeCompleteConsumer::IsNestedNameSpecifier); - CollectLookupResults(S, NextRank, Results); - } - - ProcessCodeCompleteResults(Results.data(), Results.size()); -} - -void -CodeCompleteConsumer::CodeCompleteQualifiedId(Scope *S, - NestedNameSpecifier *NNS, - bool EnteringContext) { - CXXScopeSpec SS; - SS.setScopeRep(NNS); - DeclContext *Ctx = getSema().computeDeclContext(SS, EnteringContext); - if (!Ctx) - return; - - ResultSet Results(*this); - unsigned NextRank = CollectMemberLookupResults(Ctx, 0, Results); - - // The "template" keyword can follow "::" in the grammar, but only - // put it into the grammar if the nested-name-specifier is dependent. - if (!Results.empty() && NNS->isDependent()) - Results.MaybeAddResult(Result("template", NextRank)); - - ProcessCodeCompleteResults(Results.data(), Results.size()); -} - -void CodeCompleteConsumer::CodeCompleteUsing(Scope *S) { - ResultSet Results(*this, &CodeCompleteConsumer::IsNestedNameSpecifier); - - // If we aren't in class scope, we could see the "namespace" keyword. - if (!S->isClassScope()) - Results.MaybeAddResult(Result("namespace", 0)); - - // After "using", we can see anything that would start a - // nested-name-specifier. - CollectLookupResults(S, 0, Results); - - ProcessCodeCompleteResults(Results.data(), Results.size()); -} - -void CodeCompleteConsumer::CodeCompleteUsingDirective(Scope *S) { - // After "using namespace", we expect to see a namespace name or namespace - // alias. - ResultSet Results(*this, &CodeCompleteConsumer::IsNamespaceOrAlias); - CollectLookupResults(S, 0, Results); - ProcessCodeCompleteResults(Results.data(), Results.size()); -} - -void CodeCompleteConsumer::CodeCompleteNamespaceDecl(Scope *S) { - ResultSet Results(*this, &CodeCompleteConsumer::IsNamespace); - DeclContext *Ctx = (DeclContext *)S->getEntity(); - if (!S->getParent()) - Ctx = getSema().Context.getTranslationUnitDecl(); - - if (Ctx && Ctx->isFileContext()) { - // We only want to see those namespaces that have already been defined - // within this scope, because its likely that the user is creating an - // extended namespace declaration. Keep track of the most recent - // definition of each namespace. - std::map<NamespaceDecl *, NamespaceDecl *> OrigToLatest; - for (DeclContext::specific_decl_iterator<NamespaceDecl> - NS(Ctx->decls_begin()), NSEnd(Ctx->decls_end()); - NS != NSEnd; ++NS) - OrigToLatest[NS->getOriginalNamespace()] = *NS; - - // Add the most recent definition (or extended definition) of each - // namespace to the list of results. - for (std::map<NamespaceDecl *, NamespaceDecl *>::iterator - NS = OrigToLatest.begin(), NSEnd = OrigToLatest.end(); - NS != NSEnd; ++NS) - Results.MaybeAddResult(Result(NS->second, 0)); - } - - ProcessCodeCompleteResults(Results.data(), Results.size()); -} - -void CodeCompleteConsumer::CodeCompleteNamespaceAliasDecl(Scope *S) { - // After "namespace", we expect to see a namespace or alias. - ResultSet Results(*this, &CodeCompleteConsumer::IsNamespaceOrAlias); - CollectLookupResults(S, 0, Results); - ProcessCodeCompleteResults(Results.data(), Results.size()); -} - -void CodeCompleteConsumer::CodeCompleteOperatorName(Scope *S) { - ResultSet Results(*this, &CodeCompleteConsumer::IsType); - - // Add the names of overloadable operators. -#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \ - if (std::strcmp(Spelling, "?")) \ - Results.MaybeAddResult(Result(Spelling, 0)); -#include "clang/Basic/OperatorKinds.def" - - // Add any type names visible from the current scope - unsigned NextRank = CollectLookupResults(S, 0, Results); - - // Add any type specifiers - AddTypeSpecifierResults(0, Results); - - // Add any nested-name-specifiers - Results.setFilter(&CodeCompleteConsumer::IsNestedNameSpecifier); - CollectLookupResults(S, NextRank + 1, Results); - - ProcessCodeCompleteResults(Results.data(), Results.size()); -} - -void CodeCompleteConsumer::ResultSet::MaybeAddResult(Result R) { - if (R.Kind != Result::RK_Declaration) { - // For non-declaration results, just add the result. - Results.push_back(R); - return; - } - - // Look through using declarations. - if (UsingDecl *Using = dyn_cast<UsingDecl>(R.Declaration)) - return MaybeAddResult(Result(Using->getTargetDecl(), R.Rank)); - - // Handle each declaration in an overload set separately. - if (OverloadedFunctionDecl *Ovl - = dyn_cast<OverloadedFunctionDecl>(R.Declaration)) { - for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(), - FEnd = Ovl->function_end(); - F != FEnd; ++F) - MaybeAddResult(Result(*F, R.Rank)); - - return; - } - - Decl *CanonDecl = R.Declaration->getCanonicalDecl(); - unsigned IDNS = CanonDecl->getIdentifierNamespace(); - - // Friend declarations and declarations introduced due to friends are never - // added as results. - if (isa<FriendDecl>(CanonDecl) || - (IDNS & (Decl::IDNS_OrdinaryFriend | Decl::IDNS_TagFriend))) - return; - - if (const IdentifierInfo *Id = R.Declaration->getIdentifier()) { - // __va_list_tag is a freak of nature. Find it and skip it. - if (Id->isStr("__va_list_tag") || Id->isStr("__builtin_va_list")) - return; - - // FIXME: Should we filter out other names in the implementation's - // namespace, e.g., those containing a __ or that start with _[A-Z]? - } - - // C++ constructors are never found by name lookup. - if (isa<CXXConstructorDecl>(CanonDecl)) - return; - - // Filter out any unwanted results. - if (Filter && !(Completer.*Filter)(R.Declaration)) - return; - - ShadowMap &SMap = ShadowMaps.back(); - ShadowMap::iterator I, IEnd; - for (llvm::tie(I, IEnd) = SMap.equal_range(R.Declaration->getDeclName()); - I != IEnd; ++I) { - NamedDecl *ND = I->second.first; - unsigned Index = I->second.second; - if (ND->getCanonicalDecl() == CanonDecl) { - // This is a redeclaration. Always pick the newer declaration. - I->second.first = R.Declaration; - Results[Index].Declaration = R.Declaration; - - // Pick the best rank of the two. - Results[Index].Rank = std::min(Results[Index].Rank, R.Rank); - - // We're done. - return; - } - } - - // This is a new declaration in this scope. However, check whether this - // declaration name is hidden by a similarly-named declaration in an outer - // scope. - std::list<ShadowMap>::iterator SM, SMEnd = ShadowMaps.end(); - --SMEnd; - for (SM = ShadowMaps.begin(); SM != SMEnd; ++SM) { - for (llvm::tie(I, IEnd) = SM->equal_range(R.Declaration->getDeclName()); - I != IEnd; ++I) { - // A tag declaration does not hide a non-tag declaration. - if (I->second.first->getIdentifierNamespace() == Decl::IDNS_Tag && - (IDNS & (Decl::IDNS_Member | Decl::IDNS_Ordinary | - Decl::IDNS_ObjCProtocol))) - continue; - - // Protocols are in distinct namespaces from everything else. - if (((I->second.first->getIdentifierNamespace() & Decl::IDNS_ObjCProtocol) - || (IDNS & Decl::IDNS_ObjCProtocol)) && - I->second.first->getIdentifierNamespace() != IDNS) - continue; - - // The newly-added result is hidden by an entry in the shadow map. - if (Completer.canHiddenResultBeFound(R.Declaration, I->second.first)) { - // Note that this result was hidden. - R.Hidden = true; - } else { - // This result was hidden and cannot be found; don't bother adding - // it. - return; - } - - break; - } - } - - // Make sure that any given declaration only shows up in the result set once. - if (!AllDeclsFound.insert(CanonDecl)) - return; - - // Insert this result into the set of results and into the current shadow - // map. - SMap.insert(std::make_pair(R.Declaration->getDeclName(), - std::make_pair(R.Declaration, Results.size()))); - Results.push_back(R); -} - -/// \brief Enter into a new scope. -void CodeCompleteConsumer::ResultSet::EnterNewScope() { - ShadowMaps.push_back(ShadowMap()); -} - -/// \brief Exit from the current scope. -void CodeCompleteConsumer::ResultSet::ExitScope() { - ShadowMaps.pop_back(); -} - -// Find the next outer declaration context corresponding to this scope. -static DeclContext *findOuterContext(Scope *S) { - for (S = S->getParent(); S; S = S->getParent()) - if (S->getEntity()) - return static_cast<DeclContext *>(S->getEntity())->getPrimaryContext(); - - return 0; -} - -/// \brief Collect the results of searching for declarations within the given -/// scope and its parent scopes. -/// -/// \param S the scope in which we will start looking for declarations. -/// -/// \param InitialRank the initial rank given to results in this scope. -/// Larger rank values will be used for results found in parent scopes. -unsigned CodeCompleteConsumer::CollectLookupResults(Scope *S, - unsigned InitialRank, - ResultSet &Results) { - if (!S) - return InitialRank; - - // FIXME: Using directives! - - unsigned NextRank = InitialRank; - Results.EnterNewScope(); - if (S->getEntity() && - !((DeclContext *)S->getEntity())->isFunctionOrMethod()) { - // Look into this scope's declaration context, along with any of its - // parent lookup contexts (e.g., enclosing classes), up to the point - // where we hit the context stored in the next outer scope. - DeclContext *Ctx = (DeclContext *)S->getEntity(); - DeclContext *OuterCtx = findOuterContext(S); - - for (; Ctx && Ctx->getPrimaryContext() != OuterCtx; - Ctx = Ctx->getLookupParent()) { - if (Ctx->isFunctionOrMethod()) - continue; - - NextRank = CollectMemberLookupResults(Ctx, NextRank + 1, Results); - } - } else if (!S->getParent()) { - // Look into the translation unit scope. We walk through the translation - // unit's declaration context, because the Scope itself won't have all of - // the declarations if - NextRank = CollectMemberLookupResults( - getSema().Context.getTranslationUnitDecl(), - NextRank + 1, Results); - } else { - // Walk through the declarations in this Scope. - for (Scope::decl_iterator D = S->decl_begin(), DEnd = S->decl_end(); - D != DEnd; ++D) { - if (NamedDecl *ND = dyn_cast<NamedDecl>((Decl *)((*D).get()))) - Results.MaybeAddResult(Result(ND, NextRank)); - } - - NextRank = NextRank + 1; - } - - // Lookup names in the parent scope. - NextRank = CollectLookupResults(S->getParent(), NextRank, Results); - Results.ExitScope(); - - return NextRank; -} - -/// \brief Collect the results of searching for members within the given -/// declaration context. -/// -/// \param Ctx the declaration context from which we will gather results. -/// -/// \param InitialRank the initial rank given to results in this declaration -/// context. Larger rank values will be used for, e.g., members found in -/// base classes. -/// -/// \param Results the result set that will be extended with any results -/// found within this declaration context (and, for a C++ class, its bases). -/// -/// \returns the next higher rank value, after considering all of the -/// names within this declaration context. -unsigned CodeCompleteConsumer::CollectMemberLookupResults(DeclContext *Ctx, - unsigned InitialRank, - ResultSet &Results) { - llvm::SmallPtrSet<DeclContext *, 16> Visited; - return CollectMemberLookupResults(Ctx, InitialRank, Visited, Results); -} - -/// \brief Collect the results of searching for members within the given -/// declaration context. -/// -/// \param Ctx the declaration context from which we will gather results. -/// -/// \param InitialRank the initial rank given to results in this declaration -/// context. Larger rank values will be used for, e.g., members found in -/// base classes. -/// -/// \param Visited the set of declaration contexts that have already been -/// visited. Declaration contexts will only be visited once. -/// -/// \param Results the result set that will be extended with any results -/// found within this declaration context (and, for a C++ class, its bases). -/// -/// \returns the next higher rank value, after considering all of the -/// names within this declaration context. -unsigned CodeCompleteConsumer::CollectMemberLookupResults(DeclContext *Ctx, - unsigned InitialRank, - llvm::SmallPtrSet<DeclContext *, 16> &Visited, - ResultSet &Results) { - // Make sure we don't visit the same context twice. - if (!Visited.insert(Ctx->getPrimaryContext())) - return InitialRank; - - // Enumerate all of the results in this context. - Results.EnterNewScope(); - for (DeclContext *CurCtx = Ctx->getPrimaryContext(); CurCtx; - CurCtx = CurCtx->getNextContext()) { - for (DeclContext::decl_iterator D = CurCtx->decls_begin(), - DEnd = CurCtx->decls_end(); - D != DEnd; ++D) { - if (NamedDecl *ND = dyn_cast<NamedDecl>(*D)) - Results.MaybeAddResult(Result(ND, InitialRank)); - } - } - - // Traverse the contexts of inherited classes. - unsigned NextRank = InitialRank; - if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx)) { - for (CXXRecordDecl::base_class_iterator B = Record->bases_begin(), - BEnd = Record->bases_end(); - B != BEnd; ++B) { - QualType BaseType = B->getType(); - - // Don't look into dependent bases, because name lookup can't look - // there anyway. - if (BaseType->isDependentType()) - continue; - - const RecordType *Record = BaseType->getAs<RecordType>(); - if (!Record) - continue; - - // FIXME: It would be nice to be able to determine whether referencing - // a particular member would be ambiguous. For example, given - // - // struct A { int member; }; - // struct B { int member; }; - // struct C : A, B { }; - // - // void f(C *c) { c->### } - // accessing 'member' would result in an ambiguity. However, code - // completion could be smart enough to qualify the member with the - // base class, e.g., - // - // c->B::member - // - // or - // - // c->A::member - - // Collect results from this base class (and its bases). - NextRank = std::max(NextRank, - CollectMemberLookupResults(Record->getDecl(), - InitialRank + 1, - Visited, - Results)); - } - } - - // FIXME: Look into base classes in Objective-C! - - Results.ExitScope(); - return NextRank; -} - -/// \brief Determines whether the given declaration is suitable as the -/// start of a C++ nested-name-specifier, e.g., a class or namespace. -bool CodeCompleteConsumer::IsNestedNameSpecifier(NamedDecl *ND) const { - // Allow us to find class templates, too. - if (ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(ND)) - ND = ClassTemplate->getTemplatedDecl(); - - return getSema().isAcceptableNestedNameSpecifier(ND); -} - -/// \brief Determines whether the given declaration is an enumeration. -bool CodeCompleteConsumer::IsEnum(NamedDecl *ND) const { - return isa<EnumDecl>(ND); -} - -/// \brief Determines whether the given declaration is a class or struct. -bool CodeCompleteConsumer::IsClassOrStruct(NamedDecl *ND) const { - // Allow us to find class templates, too. - if (ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(ND)) - ND = ClassTemplate->getTemplatedDecl(); - - if (RecordDecl *RD = dyn_cast<RecordDecl>(ND)) - return RD->getTagKind() == TagDecl::TK_class || - RD->getTagKind() == TagDecl::TK_struct; - - return false; -} - -/// \brief Determines whether the given declaration is a union. -bool CodeCompleteConsumer::IsUnion(NamedDecl *ND) const { - // Allow us to find class templates, too. - if (ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(ND)) - ND = ClassTemplate->getTemplatedDecl(); - - if (RecordDecl *RD = dyn_cast<RecordDecl>(ND)) - return RD->getTagKind() == TagDecl::TK_union; - - return false; -} - -/// \brief Determines whether the given declaration is a namespace. -bool CodeCompleteConsumer::IsNamespace(NamedDecl *ND) const { - return isa<NamespaceDecl>(ND); -} - -/// \brief Determines whether the given declaration is a namespace or -/// namespace alias. -bool CodeCompleteConsumer::IsNamespaceOrAlias(NamedDecl *ND) const { - return isa<NamespaceDecl>(ND) || isa<NamespaceAliasDecl>(ND); -} - -/// \brief Brief determines whether the given declaration is a namespace or -/// namespace alias. -bool CodeCompleteConsumer::IsType(NamedDecl *ND) const { - return isa<TypeDecl>(ND); -} - -namespace { - struct VISIBILITY_HIDDEN SortCodeCompleteResult { - typedef CodeCompleteConsumer::Result Result; - - bool operator()(const Result &X, const Result &Y) const { - // Sort first by rank. - if (X.Rank < Y.Rank) - return true; - else if (X.Rank > Y.Rank) - return false; - - // Result kinds are ordered by decreasing importance. - if (X.Kind < Y.Kind) - return true; - else if (X.Kind > Y.Kind) - return false; - - // Non-hidden names precede hidden names. - if (X.Hidden != Y.Hidden) - return !X.Hidden; - - // Ordering depends on the kind of result. - switch (X.Kind) { - case Result::RK_Declaration: - // Order based on the declaration names. - return X.Declaration->getDeclName() < Y.Declaration->getDeclName(); - - case Result::RK_Keyword: - return strcmp(X.Keyword, Y.Keyword) == -1; - } - - // If only our C++ compiler did control-flow warnings properly. - return false; - } - }; -} - -/// \brief Determines whether the given hidden result could be found with -/// some extra work, e.g., by qualifying the name. -/// -/// \param Hidden the declaration that is hidden by the currenly \p Visible -/// declaration. -/// -/// \param Visible the declaration with the same name that is already visible. -/// -/// \returns true if the hidden result can be found by some mechanism, -/// false otherwise. -bool CodeCompleteConsumer::canHiddenResultBeFound(NamedDecl *Hidden, - NamedDecl *Visible) { - // In C, there is no way to refer to a hidden name. - if (!getSema().getLangOptions().CPlusPlus) - return false; - - DeclContext *HiddenCtx = Hidden->getDeclContext()->getLookupContext(); - - // There is no way to qualify a name declared in a function or method. - if (HiddenCtx->isFunctionOrMethod()) - return false; - - // If the hidden and visible declarations are in |