aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2009-09-21 16:56:56 +0000
committerDouglas Gregor <dgregor@apple.com>2009-09-21 16:56:56 +0000
commit86d9a52c24d390631a888d4ff812e1b15445e0a0 (patch)
tree1f30ab2df64a31faf773231cf5ac963cb118b134
parent657f21bee4750eb28dfb4d60662919417a53d724 (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.h210
-rw-r--r--lib/Lex/Lexer.cpp25
-rw-r--r--lib/Sema/CodeCompleteConsumer.cpp851
-rw-r--r--lib/Sema/ParseAST.cpp4
-rw-r--r--lib/Sema/Sema.h5
-rw-r--r--lib/Sema/SemaCodeComplete.cpp929
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 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<CodeCompletionString>(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<TemplateTypeParmDecl>(*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<NonTypeTemplateParmDecl>(*P)) {
- if (NTTP->getIdentifier())
- PlaceholderStr = NTTP->getIdentifier()->getName();
- NTTP->getType().getAsStringInternal(PlaceholderStr,
- Context.PrintingPolicy);
- HasDefaultArg = NTTP->hasDefaultArgument();
- } else {
- assert(isa<TemplateTemplateParmDecl>(*P));
- TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*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<CodeCompletionString>(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<FunctionDecl>(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<FunctionTemplateDecl>(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<bool, 16> 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<TemplateTypeParmDecl>(Param))
- HasDefaultArg = TTP->hasDefaultArgument();
- else if (NonTypeTemplateParmDecl *NTTP
- = dyn_cast<NonTypeTemplateParmDecl>(Param))
- HasDefaultArg = NTTP->hasDefaultArgument();
- else {
- assert(isa<TemplateTemplateParmDecl>(Param));
- HasDefaultArg
- = cast<TemplateTemplateParmDecl>(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<TemplateDecl>(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 <list>
+#include <map>
+#include <vector>
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<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 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<ShadowMap> 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<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();
+
+ /// \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<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 && !(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<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 (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<ClassTemplateDecl>(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<EnumDecl>(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<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 ResultBuilder::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 ResultBuilder::IsNamespace(NamedDecl *ND) const {
+ return isa<NamespaceDecl>(ND);
+}
+
+/// \brief Determines whether the given declaration is a namespace or
+/// namespace alias.
+bool ResultBuilder::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 ResultBuilder::IsType(NamedDecl *ND) const {
+ return isa<TypeDecl>(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<DeclContext *>(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<DeclContext *, 16> &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<NamedDecl>(*D))
+ Results.MaybeAddResult(CodeCompleteConsumer::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 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<DeclContext *, 16> 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<NamedDecl>((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<CodeCompletionString>(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<TemplateTypeParmDecl>(*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<NonTypeTemplateParmDecl>(*P)) {
+ if (NTTP->getIdentifier())
+ PlaceholderStr = NTTP->getIdentifier()->getName();
+ NTTP->getType().getAsStringInternal(PlaceholderStr,
+ Context.PrintingPolicy);
+ HasDefaultArg = NTTP->hasDefaultArgument();
+ } else {
+ assert(isa<TemplateTemplateParmDecl>(*P));
+ TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*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<CodeCompletionString>(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<FunctionDecl>(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<FunctionTemplateDecl>(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<bool, 16> 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<TemplateTypeParmDecl>(Param))
+ HasDefaultArg = TTP->hasDefaultArgument();
+ else if (NonTypeTemplateParmDecl *NTTP
+ = dyn_cast<NonTypeTemplateParmDecl>(Param))
+ HasDefaultArg = NTTP->hasDefaultArgument();
+ else {
+ assert(isa<TemplateTemplateParmDecl>(Param));
+ HasDefaultArg
+ = cast<TemplateTemplateParmDecl>(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<TemplateDecl>(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<Expr *>(BaseE);
QualType BaseType = Base->getType();
-
- CodeCompleter->CodeCompleteMemberReferenceExpr(S, BaseType, IsArrow);
+
+ if (IsArrow) {
+ if (const PointerType *Ptr = BaseType->getAs<PointerType>())
+ BaseType = Ptr->getPointeeType();
+ else if (BaseType->isObjCObjectPointerType())
+ /*Do nothing*/ ;
+ else
+ return;
+ }
+
+ ResultBuilder Results(*this);
+ unsigned NextRank = 0;
+
+ if (const RecordType *Record = BaseType->getAs<RecordType>()) {
+ 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<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(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());
}