From: Douglas Gregor Date: Mon, 21 Sep 2009 16:56:56 +0000 (+0000) Subject: Refactor and simplify the CodeCompleteConsumer, so that all of the X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=86d9a52c24d390631a888d4ff812e1b15445e0a0;p=clang 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 --- 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 -#include #include #include -#include 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 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 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 > 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 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::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 &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()) - BaseType = Ptr->getPointeeType(); - else if (BaseType->isObjCObjectPointerType()) - /*Do nothing*/ ; - else - return; - } - - ResultSet Results(*this); - unsigned NextRank = 0; - - if (const RecordType *Record = BaseType->getAs()) { - 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 OrigToLatest; - for (DeclContext::specific_decl_iterator - 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::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(R.Declaration)) - return MaybeAddResult(Result(Using->getTargetDecl(), R.Rank)); - - // Handle each declaration in an overload set separately. - if (OverloadedFunctionDecl *Ovl - = dyn_cast(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(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(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::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(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((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 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 &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(*D)) - Results.MaybeAddResult(Result(ND, InitialRank)); - } - } - - // Traverse the contexts of inherited classes. - unsigned NextRank = InitialRank; - if (CXXRecordDecl *Record = dyn_cast(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(); - 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(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(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(ND)) - ND = ClassTemplate->getTemplatedDecl(); - - if (RecordDecl *RD = dyn_cast(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(ND)) - ND = ClassTemplate->getTemplatedDecl(); - - if (RecordDecl *RD = dyn_cast(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(ND); -} - -/// \brief Determines whether the given declaration is a namespace or -/// namespace alias. -bool CodeCompleteConsumer::IsNamespaceOrAlias(NamedDecl *ND) const { - return isa(ND) || isa(ND); -} - -/// \brief Brief determines whether the given declaration is a namespace or -/// namespace alias. -bool CodeCompleteConsumer::IsType(NamedDecl *ND) const { - return isa(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 different name-lookup - // contexts, then we can qualify the name of the hidden declaration. - // FIXME: Optionally compute the string needed to refer to the hidden - // name. - return HiddenCtx != Visible->getDeclContext()->getLookupContext(); -} - -/// \brief Add type specifiers for the current language as keyword results. -void CodeCompleteConsumer::AddTypeSpecifierResults(unsigned Rank, - ResultSet &Results) { - Results.MaybeAddResult(Result("short", Rank)); - Results.MaybeAddResult(Result("long", Rank)); - Results.MaybeAddResult(Result("signed", Rank)); - Results.MaybeAddResult(Result("unsigned", Rank)); - Results.MaybeAddResult(Result("void", Rank)); - Results.MaybeAddResult(Result("char", Rank)); - Results.MaybeAddResult(Result("int", Rank)); - Results.MaybeAddResult(Result("float", Rank)); - Results.MaybeAddResult(Result("double", Rank)); - Results.MaybeAddResult(Result("enum", Rank)); - Results.MaybeAddResult(Result("struct", Rank)); - Results.MaybeAddResult(Result("union", Rank)); - - if (getSema().getLangOptions().C99) { - // C99-specific - Results.MaybeAddResult(Result("_Complex", Rank)); - Results.MaybeAddResult(Result("_Imaginary", Rank)); - Results.MaybeAddResult(Result("_Bool", Rank)); - } - - if (getSema().getLangOptions().CPlusPlus) { - // C++-specific - Results.MaybeAddResult(Result("bool", Rank)); - Results.MaybeAddResult(Result("class", Rank)); - Results.MaybeAddResult(Result("typename", Rank)); - Results.MaybeAddResult(Result("wchar_t", Rank)); - - if (getSema().getLangOptions().CPlusPlus0x) { - Results.MaybeAddResult(Result("char16_t", Rank)); - Results.MaybeAddResult(Result("char32_t", Rank)); - Results.MaybeAddResult(Result("decltype", Rank)); - } - } - - // GNU extensions - if (getSema().getLangOptions().GNUMode) { - // FIXME: Enable when we actually support decimal floating point. - // Results.MaybeAddResult(Result("_Decimal32", Rank)); - // Results.MaybeAddResult(Result("_Decimal64", Rank)); - // Results.MaybeAddResult(Result("_Decimal128", Rank)); - Results.MaybeAddResult(Result("typeof", Rank)); - } -} - -/// \brief Add function parameter chunks to the given code completion string. -static void AddFunctionParameterChunks(ASTContext &Context, - FunctionDecl *Function, - CodeCompletionString *Result) { - CodeCompletionString *CCStr = Result; - - for (unsigned P = 0, N = Function->getNumParams(); P != N; ++P) { - ParmVarDecl *Param = Function->getParamDecl(P); - - if (Param->hasDefaultArg()) { - // When we see an optional default argument, put that argument and - // the remaining default arguments into a new, optional string. - CodeCompletionString *Opt = new CodeCompletionString; - CCStr->AddOptionalChunk(std::auto_ptr(Opt)); - CCStr = Opt; - } - - if (P != 0) - CCStr->AddTextChunk(", "); - - // Format the placeholder string. - std::string PlaceholderStr; - if (Param->getIdentifier()) - PlaceholderStr = Param->getIdentifier()->getName(); - - Param->getType().getAsStringInternal(PlaceholderStr, - Context.PrintingPolicy); - - // Add the placeholder string. - CCStr->AddPlaceholderChunk(PlaceholderStr.c_str()); - } -} - -/// \brief Add template parameter chunks to the given code completion string. -static void AddTemplateParameterChunks(ASTContext &Context, - TemplateDecl *Template, - CodeCompletionString *Result, - unsigned MaxParameters = 0) { - CodeCompletionString *CCStr = Result; - bool FirstParameter = true; - - TemplateParameterList *Params = Template->getTemplateParameters(); - TemplateParameterList::iterator PEnd = Params->end(); - if (MaxParameters) - PEnd = Params->begin() + MaxParameters; - for (TemplateParameterList::iterator P = Params->begin(); P != PEnd; ++P) { - bool HasDefaultArg = false; - std::string PlaceholderStr; - if (TemplateTypeParmDecl *TTP = dyn_cast(*P)) { - if (TTP->wasDeclaredWithTypename()) - PlaceholderStr = "typename"; - else - PlaceholderStr = "class"; - - if (TTP->getIdentifier()) { - PlaceholderStr += ' '; - PlaceholderStr += TTP->getIdentifier()->getName(); - } - - HasDefaultArg = TTP->hasDefaultArgument(); - } else if (NonTypeTemplateParmDecl *NTTP - = dyn_cast(*P)) { - if (NTTP->getIdentifier()) - PlaceholderStr = NTTP->getIdentifier()->getName(); - NTTP->getType().getAsStringInternal(PlaceholderStr, - Context.PrintingPolicy); - HasDefaultArg = NTTP->hasDefaultArgument(); - } else { - assert(isa(*P)); - TemplateTemplateParmDecl *TTP = cast(*P); - - // Since putting the template argument list into the placeholder would - // be very, very long, we just use an abbreviation. - PlaceholderStr = "template<...> class"; - if (TTP->getIdentifier()) { - PlaceholderStr += ' '; - PlaceholderStr += TTP->getIdentifier()->getName(); - } - - HasDefaultArg = TTP->hasDefaultArgument(); - } - - if (HasDefaultArg) { - // When we see an optional default argument, put that argument and - // the remaining default arguments into a new, optional string. - CodeCompletionString *Opt = new CodeCompletionString; - CCStr->AddOptionalChunk(std::auto_ptr(Opt)); - CCStr = Opt; - } - - if (FirstParameter) - FirstParameter = false; - else - CCStr->AddTextChunk(", "); - - // Add the placeholder string. - CCStr->AddPlaceholderChunk(PlaceholderStr.c_str()); - } -} - -/// \brief If possible, create a new code completion string for the given -/// result. -/// -/// \returns Either a new, heap-allocated code completion string describing -/// how to use this result, or NULL to indicate that the string or name of the -/// result is all that is needed. -CodeCompletionString * -CodeCompleteConsumer::CreateCodeCompletionString(Result R) { - if (R.Kind != Result::RK_Declaration) - return 0; - - NamedDecl *ND = R.Declaration; - - if (FunctionDecl *Function = dyn_cast(ND)) { - CodeCompletionString *Result = new CodeCompletionString; - Result->AddTextChunk(Function->getNameAsString().c_str()); - Result->AddTextChunk("("); - AddFunctionParameterChunks(getSema().Context, Function, Result); - Result->AddTextChunk(")"); - return Result; - } - - if (FunctionTemplateDecl *FunTmpl = dyn_cast(ND)) { - CodeCompletionString *Result = new CodeCompletionString; - FunctionDecl *Function = FunTmpl->getTemplatedDecl(); - Result->AddTextChunk(Function->getNameAsString().c_str()); - - // Figure out which template parameters are deduced (or have default - // arguments). - llvm::SmallVector Deduced; - getSema().MarkDeducedTemplateParameters(FunTmpl, Deduced); - unsigned LastDeducibleArgument; - for (LastDeducibleArgument = Deduced.size(); LastDeducibleArgument > 0; - --LastDeducibleArgument) { - if (!Deduced[LastDeducibleArgument - 1]) { - // C++0x: Figure out if the template argument has a default. If so, - // the user doesn't need to type this argument. - // FIXME: We need to abstract template parameters better! - bool HasDefaultArg = false; - NamedDecl *Param = FunTmpl->getTemplateParameters()->getParam( - LastDeducibleArgument - 1); - if (TemplateTypeParmDecl *TTP = dyn_cast(Param)) - HasDefaultArg = TTP->hasDefaultArgument(); - else if (NonTypeTemplateParmDecl *NTTP - = dyn_cast(Param)) - HasDefaultArg = NTTP->hasDefaultArgument(); - else { - assert(isa(Param)); - HasDefaultArg - = cast(Param)->hasDefaultArgument(); - } - - if (!HasDefaultArg) - break; - } - } - - if (LastDeducibleArgument) { - // Some of the function template arguments cannot be deduced from a - // function call, so we introduce an explicit template argument list - // containing all of the arguments up to the first deducible argument. - Result->AddTextChunk("<"); - AddTemplateParameterChunks(getSema().Context, FunTmpl, Result, - LastDeducibleArgument); - Result->AddTextChunk(">"); - } - - // Add the function parameters - Result->AddTextChunk("("); - AddFunctionParameterChunks(getSema().Context, Function, Result); - Result->AddTextChunk(")"); - return Result; - } - - if (TemplateDecl *Template = dyn_cast(ND)) { - CodeCompletionString *Result = new CodeCompletionString; - Result->AddTextChunk(Template->getNameAsString().c_str()); - Result->AddTextChunk("<"); - AddTemplateParameterChunks(getSema().Context, Template, Result); - Result->AddTextChunk(">"); - return Result; - } - - return 0; -} +CodeCompleteConsumer::~CodeCompleteConsumer() { } void PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Result *Results, unsigned NumResults) { - // Sort the results by rank/kind/etc. - std::stable_sort(Results, Results + NumResults, SortCodeCompleteResult()); - // Print the results. for (unsigned I = 0; I != NumResults; ++I) { switch (Results[I].Kind) { @@ -943,7 +101,8 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Result *Results, << Results[I].Rank; if (Results[I].Hidden) OS << " (Hidden)"; - if (CodeCompletionString *CCS = CreateCodeCompletionString(Results[I])) { + if (CodeCompletionString *CCS + = Results[I].CreateCodeCompletionString(SemaRef)) { OS << " : " << CCS->getAsString(); delete CCS; } @@ -960,5 +119,5 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Result *Results, // Once we've printed the code-completion results, suppress remaining // diagnostics. // FIXME: Move this somewhere else! - getSema().PP.getDiagnostics().setSuppressAllDiagnostics(); + SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics(); } diff --git a/lib/Sema/ParseAST.cpp b/lib/Sema/ParseAST.cpp index be19b7e3d9..d09af0a450 100644 --- a/lib/Sema/ParseAST.cpp +++ b/lib/Sema/ParseAST.cpp @@ -64,8 +64,10 @@ void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer, } CodeCompleteConsumer *CodeCompleter = 0; - if (CreateCodeCompleter) + if (CreateCodeCompleter) { CodeCompleter = CreateCodeCompleter(S, CreateCodeCompleterData); + S.setCodeCompleteConsumer(CodeCompleter); + } Parser::DeclGroupPtrTy ADecl; diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index a95fac9dcd..d2bbc4cbb5 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -3628,12 +3628,7 @@ public: /// \name Code completion //@{ -private: - friend class CodeCompleteConsumer; - void setCodeCompleteConsumer(CodeCompleteConsumer *CCC); - -public: virtual void CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *Base, SourceLocation OpLoc, bool IsArrow); diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index adb0469cf0..0032ab5ff7 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -12,6 +12,10 @@ //===----------------------------------------------------------------------===// #include "Sema.h" #include "clang/Sema/CodeCompleteConsumer.h" +#include "llvm/ADT/SmallPtrSet.h" +#include +#include +#include using namespace clang; @@ -22,45 +26,861 @@ void Sema::setCodeCompleteConsumer(CodeCompleteConsumer *CCC) { CodeCompleter = CCC; } +namespace { + /// \brief A container of code-completion results. + class ResultBuilder { + 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 (ResultBuilder::*LookupFilter)(NamedDecl *) const; + + typedef CodeCompleteConsumer::Result Result; + + private: + /// \brief The actual results we have found. + std::vector 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 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 > ShadowMap; + + /// \brief The semantic analysis object for which results are being + /// produced. + Sema &SemaRef; + + /// \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 ShadowMaps; + + public: + explicit ResultBuilder(Sema &SemaRef, LookupFilter Filter = 0) + : SemaRef(SemaRef), Filter(Filter) { } + + /// \brief Set the filter used for code-completion results. + void setFilter(LookupFilter Filter) { + this->Filter = Filter; + } + + typedef std::vector::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(); + + /// \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; + //@} + }; +} + +/// \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. +static bool canHiddenResultBeFound(const LangOptions &LangOpts, + NamedDecl *Hidden, NamedDecl *Visible) { + // In C, there is no way to refer to a hidden name. + if (!LangOpts.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 different name-lookup + // contexts, then we can qualify the name of the hidden declaration. + // FIXME: Optionally compute the string needed to refer to the hidden + // name. + return HiddenCtx != Visible->getDeclContext()->getLookupContext(); +} + +void ResultBuilder::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(R.Declaration)) + return MaybeAddResult(Result(Using->getTargetDecl(), R.Rank)); + + // Handle each declaration in an overload set separately. + if (OverloadedFunctionDecl *Ovl + = dyn_cast(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(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(CanonDecl)) + return; + + // Filter out any unwanted results. + if (Filter && !(this->*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::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 (canHiddenResultBeFound(SemaRef.getLangOptions(), 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 ResultBuilder::EnterNewScope() { + ShadowMaps.push_back(ShadowMap()); +} + +/// \brief Exit from the current scope. +void ResultBuilder::ExitScope() { + ShadowMaps.pop_back(); +} + +/// \brief Determines whether the given declaration is suitable as the +/// start of a C++ nested-name-specifier, e.g., a class or namespace. +bool ResultBuilder::IsNestedNameSpecifier(NamedDecl *ND) const { + // Allow us to find class templates, too. + if (ClassTemplateDecl *ClassTemplate = dyn_cast(ND)) + ND = ClassTemplate->getTemplatedDecl(); + + return SemaRef.isAcceptableNestedNameSpecifier(ND); +} + +/// \brief Determines whether the given declaration is an enumeration. +bool ResultBuilder::IsEnum(NamedDecl *ND) const { + return isa(ND); +} + +/// \brief Determines whether the given declaration is a class or struct. +bool ResultBuilder::IsClassOrStruct(NamedDecl *ND) const { + // Allow us to find class templates, too. + if (ClassTemplateDecl *ClassTemplate = dyn_cast(ND)) + ND = ClassTemplate->getTemplatedDecl(); + + if (RecordDecl *RD = dyn_cast(ND)) + return RD->getTagKind() == TagDecl::TK_class || + RD->getTagKind() == TagDecl::TK_struct; + + return false; +} + +/// \brief Determines whether the given declaration is a union. +bool ResultBuilder::IsUnion(NamedDecl *ND) const { + // Allow us to find class templates, too. + if (ClassTemplateDecl *ClassTemplate = dyn_cast(ND)) + ND = ClassTemplate->getTemplatedDecl(); + + if (RecordDecl *RD = dyn_cast(ND)) + return RD->getTagKind() == TagDecl::TK_union; + + return false; +} + +/// \brief Determines whether the given declaration is a namespace. +bool ResultBuilder::IsNamespace(NamedDecl *ND) const { + return isa(ND); +} + +/// \brief Determines whether the given declaration is a namespace or +/// namespace alias. +bool ResultBuilder::IsNamespaceOrAlias(NamedDecl *ND) const { + return isa(ND) || isa(ND); +} + +/// \brief Brief determines whether the given declaration is a namespace or +/// namespace alias. +bool ResultBuilder::IsType(NamedDecl *ND) const { + return isa(ND); +} + +// 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(S->getEntity())->getPrimaryContext(); + + return 0; +} + +/// \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. +static unsigned CollectMemberLookupResults(DeclContext *Ctx, + unsigned InitialRank, + llvm::SmallPtrSet &Visited, + ResultBuilder &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(*D)) + Results.MaybeAddResult(CodeCompleteConsumer::Result(ND, InitialRank)); + } + } + + // Traverse the contexts of inherited classes. + unsigned NextRank = InitialRank; + if (CXXRecordDecl *Record = dyn_cast(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(); + 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 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. +static unsigned CollectMemberLookupResults(DeclContext *Ctx, + unsigned InitialRank, + ResultBuilder &Results) { + llvm::SmallPtrSet Visited; + return CollectMemberLookupResults(Ctx, InitialRank, Visited, Results); +} + +/// \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. +/// +/// \param Results the builder object that will receive each result. +static unsigned CollectLookupResults(Scope *S, + TranslationUnitDecl *TranslationUnit, + unsigned InitialRank, + ResultBuilder &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 we loaded a precompiled header. + // FIXME: We would like the translation unit's Scope object to point to the + // translation unit, so we don't need this special "if" branch. However, + // doing so would force the normal C++ name-lookup code to look into the + // translation unit decl when the IdentifierInfo chains would suffice. + // Once we fix that problem (which is part of a more general "don't look + // in DeclContexts unless we have to" optimization), we can eliminate the + // TranslationUnit parameter entirely. + NextRank = CollectMemberLookupResults(TranslationUnit, 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((Decl *)((*D).get()))) + Results.MaybeAddResult(CodeCompleteConsumer::Result(ND, NextRank)); + } + + NextRank = NextRank + 1; + } + + // Lookup names in the parent scope. + NextRank = CollectLookupResults(S->getParent(), TranslationUnit, NextRank, + Results); + Results.ExitScope(); + + return NextRank; +} + +/// \brief Add type specifiers for the current language as keyword results. +static void AddTypeSpecifierResults(const LangOptions &LangOpts, unsigned Rank, + ResultBuilder &Results) { + typedef CodeCompleteConsumer::Result Result; + Results.MaybeAddResult(Result("short", Rank)); + Results.MaybeAddResult(Result("long", Rank)); + Results.MaybeAddResult(Result("signed", Rank)); + Results.MaybeAddResult(Result("unsigned", Rank)); + Results.MaybeAddResult(Result("void", Rank)); + Results.MaybeAddResult(Result("char", Rank)); + Results.MaybeAddResult(Result("int", Rank)); + Results.MaybeAddResult(Result("float", Rank)); + Results.MaybeAddResult(Result("double", Rank)); + Results.MaybeAddResult(Result("enum", Rank)); + Results.MaybeAddResult(Result("struct", Rank)); + Results.MaybeAddResult(Result("union", Rank)); + + if (LangOpts.C99) { + // C99-specific + Results.MaybeAddResult(Result("_Complex", Rank)); + Results.MaybeAddResult(Result("_Imaginary", Rank)); + Results.MaybeAddResult(Result("_Bool", Rank)); + } + + if (LangOpts.CPlusPlus) { + // C++-specific + Results.MaybeAddResult(Result("bool", Rank)); + Results.MaybeAddResult(Result("class", Rank)); + Results.MaybeAddResult(Result("typename", Rank)); + Results.MaybeAddResult(Result("wchar_t", Rank)); + + if (LangOpts.CPlusPlus0x) { + Results.MaybeAddResult(Result("char16_t", Rank)); + Results.MaybeAddResult(Result("char32_t", Rank)); + Results.MaybeAddResult(Result("decltype", Rank)); + } + } + + // GNU extensions + if (LangOpts.GNUMode) { + // FIXME: Enable when we actually support decimal floating point. + // Results.MaybeAddResult(Result("_Decimal32", Rank)); + // Results.MaybeAddResult(Result("_Decimal64", Rank)); + // Results.MaybeAddResult(Result("_Decimal128", Rank)); + Results.MaybeAddResult(Result("typeof", Rank)); + } +} + +/// \brief Add function parameter chunks to the given code completion string. +static void AddFunctionParameterChunks(ASTContext &Context, + FunctionDecl *Function, + CodeCompletionString *Result) { + CodeCompletionString *CCStr = Result; + + for (unsigned P = 0, N = Function->getNumParams(); P != N; ++P) { + ParmVarDecl *Param = Function->getParamDecl(P); + + if (Param->hasDefaultArg()) { + // When we see an optional default argument, put that argument and + // the remaining default arguments into a new, optional string. + CodeCompletionString *Opt = new CodeCompletionString; + CCStr->AddOptionalChunk(std::auto_ptr(Opt)); + CCStr = Opt; + } + + if (P != 0) + CCStr->AddTextChunk(", "); + + // Format the placeholder string. + std::string PlaceholderStr; + if (Param->getIdentifier()) + PlaceholderStr = Param->getIdentifier()->getName(); + + Param->getType().getAsStringInternal(PlaceholderStr, + Context.PrintingPolicy); + + // Add the placeholder string. + CCStr->AddPlaceholderChunk(PlaceholderStr.c_str()); + } +} + +/// \brief Add template parameter chunks to the given code completion string. +static void AddTemplateParameterChunks(ASTContext &Context, + TemplateDecl *Template, + CodeCompletionString *Result, + unsigned MaxParameters = 0) { + CodeCompletionString *CCStr = Result; + bool FirstParameter = true; + + TemplateParameterList *Params = Template->getTemplateParameters(); + TemplateParameterList::iterator PEnd = Params->end(); + if (MaxParameters) + PEnd = Params->begin() + MaxParameters; + for (TemplateParameterList::iterator P = Params->begin(); P != PEnd; ++P) { + bool HasDefaultArg = false; + std::string PlaceholderStr; + if (TemplateTypeParmDecl *TTP = dyn_cast(*P)) { + if (TTP->wasDeclaredWithTypename()) + PlaceholderStr = "typename"; + else + PlaceholderStr = "class"; + + if (TTP->getIdentifier()) { + PlaceholderStr += ' '; + PlaceholderStr += TTP->getIdentifier()->getName(); + } + + HasDefaultArg = TTP->hasDefaultArgument(); + } else if (NonTypeTemplateParmDecl *NTTP + = dyn_cast(*P)) { + if (NTTP->getIdentifier()) + PlaceholderStr = NTTP->getIdentifier()->getName(); + NTTP->getType().getAsStringInternal(PlaceholderStr, + Context.PrintingPolicy); + HasDefaultArg = NTTP->hasDefaultArgument(); + } else { + assert(isa(*P)); + TemplateTemplateParmDecl *TTP = cast(*P); + + // Since putting the template argument list into the placeholder would + // be very, very long, we just use an abbreviation. + PlaceholderStr = "template<...> class"; + if (TTP->getIdentifier()) { + PlaceholderStr += ' '; + PlaceholderStr += TTP->getIdentifier()->getName(); + } + + HasDefaultArg = TTP->hasDefaultArgument(); + } + + if (HasDefaultArg) { + // When we see an optional default argument, put that argument and + // the remaining default arguments into a new, optional string. + CodeCompletionString *Opt = new CodeCompletionString; + CCStr->AddOptionalChunk(std::auto_ptr(Opt)); + CCStr = Opt; + } + + if (FirstParameter) + FirstParameter = false; + else + CCStr->AddTextChunk(", "); + + // Add the placeholder string. + CCStr->AddPlaceholderChunk(PlaceholderStr.c_str()); + } +} + +/// \brief If possible, create a new code completion string for the given +/// result. +/// +/// \returns Either a new, heap-allocated code completion string describing +/// how to use this result, or NULL to indicate that the string or name of the +/// result is all that is needed. +CodeCompletionString * +CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) { + if (Kind != RK_Declaration) + return 0; + + NamedDecl *ND = Declaration; + + if (FunctionDecl *Function = dyn_cast(ND)) { + CodeCompletionString *Result = new CodeCompletionString; + Result->AddTextChunk(Function->getNameAsString().c_str()); + Result->AddTextChunk("("); + AddFunctionParameterChunks(S.Context, Function, Result); + Result->AddTextChunk(")"); + return Result; + } + + if (FunctionTemplateDecl *FunTmpl = dyn_cast(ND)) { + CodeCompletionString *Result = new CodeCompletionString; + FunctionDecl *Function = FunTmpl->getTemplatedDecl(); + Result->AddTextChunk(Function->getNameAsString().c_str()); + + // Figure out which template parameters are deduced (or have default + // arguments). + llvm::SmallVector Deduced; + S.MarkDeducedTemplateParameters(FunTmpl, Deduced); + unsigned LastDeducibleArgument; + for (LastDeducibleArgument = Deduced.size(); LastDeducibleArgument > 0; + --LastDeducibleArgument) { + if (!Deduced[LastDeducibleArgument - 1]) { + // C++0x: Figure out if the template argument has a default. If so, + // the user doesn't need to type this argument. + // FIXME: We need to abstract template parameters better! + bool HasDefaultArg = false; + NamedDecl *Param = FunTmpl->getTemplateParameters()->getParam( + LastDeducibleArgument - 1); + if (TemplateTypeParmDecl *TTP = dyn_cast(Param)) + HasDefaultArg = TTP->hasDefaultArgument(); + else if (NonTypeTemplateParmDecl *NTTP + = dyn_cast(Param)) + HasDefaultArg = NTTP->hasDefaultArgument(); + else { + assert(isa(Param)); + HasDefaultArg + = cast(Param)->hasDefaultArgument(); + } + + if (!HasDefaultArg) + break; + } + } + + if (LastDeducibleArgument) { + // Some of the function template arguments cannot be deduced from a + // function call, so we introduce an explicit template argument list + // containing all of the arguments up to the first deducible argument. + Result->AddTextChunk("<"); + AddTemplateParameterChunks(S.Context, FunTmpl, Result, + LastDeducibleArgument); + Result->AddTextChunk(">"); + } + + // Add the function parameters + Result->AddTextChunk("("); + AddFunctionParameterChunks(S.Context, Function, Result); + Result->AddTextChunk(")"); + return Result; + } + + if (TemplateDecl *Template = dyn_cast(ND)) { + CodeCompletionString *Result = new CodeCompletionString; + Result->AddTextChunk(Template->getNameAsString().c_str()); + Result->AddTextChunk("<"); + AddTemplateParameterChunks(S.Context, Template, Result); + Result->AddTextChunk(">"); + return Result; + } + + return 0; +} + +namespace { + struct 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; + } + + // Silence GCC warning. + return false; + } + }; +} + +static void HandleCodeCompleteResults(CodeCompleteConsumer *CodeCompleter, + CodeCompleteConsumer::Result *Results, + unsigned NumResults) { + // Sort the results by rank/kind/etc. + std::stable_sort(Results, Results + NumResults, SortCodeCompleteResult()); + + if (CodeCompleter) + CodeCompleter->ProcessCodeCompleteResults(Results, NumResults); +} + void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE, SourceLocation OpLoc, bool IsArrow) { if (!BaseE || !CodeCompleter) return; + typedef CodeCompleteConsumer::Result Result; + Expr *Base = static_cast(BaseE); QualType BaseType = Base->getType(); - - CodeCompleter->CodeCompleteMemberReferenceExpr(S, BaseType, IsArrow); + + if (IsArrow) { + if (const PointerType *Ptr = BaseType->getAs()) + BaseType = Ptr->getPointeeType(); + else if (BaseType->isObjCObjectPointerType()) + /*Do nothing*/ ; + else + return; + } + + ResultBuilder Results(*this); + unsigned NextRank = 0; + + if (const RecordType *Record = BaseType->getAs()) { + NextRank = CollectMemberLookupResults(Record->getDecl(), NextRank, Results); + + if (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(&ResultBuilder::IsNestedNameSpecifier); + CollectLookupResults(S, Context.getTranslationUnitDecl(), NextRank, + Results); + } + + // Hand off the results found for code completion. + HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); + + // We're done! + return; + } } void Sema::CodeCompleteTag(Scope *S, unsigned TagSpec) { if (!CodeCompleter) return; - TagDecl::TagKind TK; + typedef CodeCompleteConsumer::Result Result; + ResultBuilder::LookupFilter Filter = 0; switch ((DeclSpec::TST)TagSpec) { case DeclSpec::TST_enum: - TK = TagDecl::TK_enum; + Filter = &ResultBuilder::IsEnum; break; case DeclSpec::TST_union: - TK = TagDecl::TK_union; + Filter = &ResultBuilder::IsUnion; break; case DeclSpec::TST_struct: - TK = TagDecl::TK_struct; - break; - case DeclSpec::TST_class: - TK = TagDecl::TK_class; + Filter = &ResultBuilder::IsClassOrStruct; break; default: assert(false && "Unknown type specifier kind in CodeCompleteTag"); return; } - CodeCompleter->CodeCompleteTag(S, TK); + + ResultBuilder Results(*this, Filter); + unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(), + 0, Results); + + if (getLangOptions().CPlusPlus) { + // We could have the start of a nested-name-specifier. Add those + // results as well. + Results.setFilter(&ResultBuilder::IsNestedNameSpecifier); + CollectLookupResults(S, Context.getTranslationUnitDecl(), NextRank, + Results); + } + + HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); } void Sema::CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS, @@ -68,43 +888,116 @@ void Sema::CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS, if (!SS.getScopeRep() || !CodeCompleter) return; - CodeCompleter->CodeCompleteQualifiedId(S, - (NestedNameSpecifier *)SS.getScopeRep(), - EnteringContext); + DeclContext *Ctx = computeDeclContext(SS, EnteringContext); + if (!Ctx) + return; + + ResultBuilder 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. + NestedNameSpecifier *NNS = (NestedNameSpecifier *)SS.getScopeRep(); + if (!Results.empty() && NNS->isDependent()) + Results.MaybeAddResult(CodeCompleteConsumer::Result("template", NextRank)); + + HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); } void Sema::CodeCompleteUsing(Scope *S) { if (!CodeCompleter) return; - CodeCompleter->CodeCompleteUsing(S); + ResultBuilder Results(*this, &ResultBuilder::IsNestedNameSpecifier); + + // If we aren't in class scope, we could see the "namespace" keyword. + if (!S->isClassScope()) + Results.MaybeAddResult(CodeCompleteConsumer::Result("namespace", 0)); + + // After "using", we can see anything that would start a + // nested-name-specifier. + CollectLookupResults(S, Context.getTranslationUnitDecl(), 0, Results); + + HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); } void Sema::CodeCompleteUsingDirective(Scope *S) { if (!CodeCompleter) return; - CodeCompleter->CodeCompleteUsingDirective(S); + // After "using namespace", we expect to see a namespace name or namespace + // alias. + ResultBuilder Results(*this, &ResultBuilder::IsNamespaceOrAlias); + CollectLookupResults(S, Context.getTranslationUnitDecl(), 0, Results); + HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); } void Sema::CodeCompleteNamespaceDecl(Scope *S) { if (!CodeCompleter) return; - CodeCompleter->CodeCompleteNamespaceDecl(S); + ResultBuilder Results(*this, &ResultBuilder::IsNamespace); + DeclContext *Ctx = (DeclContext *)S->getEntity(); + if (!S->getParent()) + Ctx = 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 OrigToLatest; + for (DeclContext::specific_decl_iterator + 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::iterator + NS = OrigToLatest.begin(), NSEnd = OrigToLatest.end(); + NS != NSEnd; ++NS) + Results.MaybeAddResult(CodeCompleteConsumer::Result(NS->second, 0)); + } + + HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); } void Sema::CodeCompleteNamespaceAliasDecl(Scope *S) { if (!CodeCompleter) return; - CodeCompleter->CodeCompleteNamespaceAliasDecl(S); + // After "namespace", we expect to see a namespace or alias. + ResultBuilder Results(*this, &ResultBuilder::IsNamespaceOrAlias); + CollectLookupResults(S, Context.getTranslationUnitDecl(), 0, Results); + HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); } void Sema::CodeCompleteOperatorName(Scope *S) { if (!CodeCompleter) return; + + typedef CodeCompleteConsumer::Result Result; + ResultBuilder Results(*this, &ResultBuilder::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, Context.getTranslationUnitDecl(), + 0, Results); + + // Add any type specifiers + AddTypeSpecifierResults(getLangOptions(), 0, Results); + + // Add any nested-name-specifiers + Results.setFilter(&ResultBuilder::IsNestedNameSpecifier); + CollectLookupResults(S, Context.getTranslationUnitDecl(), NextRank + 1, + Results); - CodeCompleter->CodeCompleteOperatorName(S); + HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); }