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