aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2010-08-15 06:18:01 +0000
committerDouglas Gregor <dgregor@apple.com>2010-08-15 06:18:01 +0000
commit8071e4212ae08f8014e0c3ae6d18b7388003a5cc (patch)
treeea359a2c105912267f6e067eef19639c5fc48cdc /lib
parentde7a0fcdf9f30cb5a97aab614f3975d93cd9926f (diff)
Extend the code-completion caching infrastructure to include global
declarations (in addition to macros). Each kind of declaration maps to a certain set of completion contexts, and the ASTUnit completion logic introduces the completion strings for those declarations if the actual code-completion occurs in one of the contexts where it matters. There are a few new code-completion-context kinds. Without these, certain completions (e.g., after "using namespace") would need to suppress all global completions, which would be unfortunate. Note that we don't get the priorities right for global completions, because we don't have enough type information. We'll need a way to compare types in an ASTContext-agnostic way before this can be implemented. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@111093 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r--lib/Frontend/ASTUnit.cpp96
-rw-r--r--lib/Frontend/CompilerInstance.cpp8
-rw-r--r--lib/Frontend/CompilerInvocation.cpp4
-rw-r--r--lib/Sema/SemaCodeComplete.cpp57
-rw-r--r--lib/Sema/SemaLookup.cpp39
5 files changed, 170 insertions, 34 deletions
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index e6bae6b727..8d49d4e786 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -88,6 +88,79 @@ void ASTUnit::CleanTemporaryFiles() {
TemporaryFiles.clear();
}
+/// \brief Determine the set of code-completion contexts in which this
+/// declaration should be shown.
+static unsigned getDeclShowContexts(NamedDecl *ND,
+ const LangOptions &LangOpts) {
+ if (isa<UsingShadowDecl>(ND))
+ ND = dyn_cast<NamedDecl>(ND->getUnderlyingDecl());
+ if (!ND)
+ return 0;
+
+ unsigned Contexts = 0;
+ if (isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(ND) ||
+ isa<ClassTemplateDecl>(ND) || isa<TemplateTemplateParmDecl>(ND)) {
+ // Types can appear in these contexts.
+ if (LangOpts.CPlusPlus || !isa<TagDecl>(ND))
+ Contexts |= (1 << (CodeCompletionContext::CCC_TopLevel - 1))
+ | (1 << (CodeCompletionContext::CCC_ObjCIvarList - 1))
+ | (1 << (CodeCompletionContext::CCC_ClassStructUnion - 1))
+ | (1 << (CodeCompletionContext::CCC_Statement - 1))
+ | (1 << (CodeCompletionContext::CCC_Type - 1));
+
+ // In C++, types can appear in expressions contexts (for functional casts).
+ if (LangOpts.CPlusPlus)
+ Contexts |= (1 << (CodeCompletionContext::CCC_Expression - 1));
+
+ // In Objective-C, message sends can send interfaces. In Objective-C++,
+ // all types are available due to functional casts.
+ if (LangOpts.CPlusPlus || isa<ObjCInterfaceDecl>(ND))
+ Contexts |= (1 << (CodeCompletionContext::CCC_ObjCMessageReceiver - 1));
+
+ // Deal with tag names.
+ if (isa<EnumDecl>(ND)) {
+ Contexts |= (1 << (CodeCompletionContext::CCC_EnumTag - 1));
+
+ // Part of the nested-name-specifier.
+ if (LangOpts.CPlusPlus0x)
+ Contexts |= (1 << (CodeCompletionContext::CCC_MemberAccess - 1));
+ } else if (RecordDecl *Record = dyn_cast<RecordDecl>(ND)) {
+ if (Record->isUnion())
+ Contexts |= (1 << (CodeCompletionContext::CCC_UnionTag - 1));
+ else
+ Contexts |= (1 << (CodeCompletionContext::CCC_ClassOrStructTag - 1));
+
+ // Part of the nested-name-specifier.
+ if (LangOpts.CPlusPlus)
+ Contexts |= (1 << (CodeCompletionContext::CCC_MemberAccess - 1));
+ }
+ } else if (isa<ValueDecl>(ND) || isa<FunctionTemplateDecl>(ND)) {
+ // Values can appear in these contexts.
+ Contexts = (1 << (CodeCompletionContext::CCC_Statement - 1))
+ | (1 << (CodeCompletionContext::CCC_Expression - 1))
+ | (1 << (CodeCompletionContext::CCC_ObjCMessageReceiver - 1));
+ } else if (isa<ObjCProtocolDecl>(ND)) {
+ Contexts = (1 << (CodeCompletionContext::CCC_ObjCProtocolName - 1));
+ } else if (isa<NamespaceDecl>(ND) || isa<NamespaceAliasDecl>(ND)) {
+ Contexts = (1 << (CodeCompletionContext::CCC_TopLevel - 1))
+ | (1 << (CodeCompletionContext::CCC_ObjCIvarList - 1))
+ | (1 << (CodeCompletionContext::CCC_ClassStructUnion - 1))
+ | (1 << (CodeCompletionContext::CCC_Statement - 1))
+ | (1 << (CodeCompletionContext::CCC_Expression - 1))
+ | (1 << (CodeCompletionContext::CCC_ObjCMessageReceiver - 1))
+ | (1 << (CodeCompletionContext::CCC_Namespace - 1));
+
+ // Part of the nested-name-specifier.
+ Contexts |= (1 << (CodeCompletionContext::CCC_MemberAccess - 1))
+ | (1 << (CodeCompletionContext::CCC_EnumTag - 1))
+ | (1 << (CodeCompletionContext::CCC_UnionTag - 1))
+ | (1 << (CodeCompletionContext::CCC_ClassOrStructTag - 1))
+ | (1 << (CodeCompletionContext::CCC_Type - 1));
+ }
+
+ return Contexts;
+}
+
void ASTUnit::CacheCodeCompletionResults() {
if (!TheSema)
return;
@@ -111,10 +184,17 @@ void ASTUnit::CacheCodeCompletionResults() {
// Translate global code completions into cached completions.
for (unsigned I = 0, N = Results.size(); I != N; ++I) {
switch (Results[I].Kind) {
- case Result::RK_Declaration:
- // FIXME: Handle declarations!
+ case Result::RK_Declaration: {
+ CachedCodeCompletionResult CachedResult;
+ CachedResult.Completion = Results[I].CreateCodeCompletionString(*TheSema);
+ CachedResult.ShowInContexts = getDeclShowContexts(Results[I].Declaration,
+ Ctx->getLangOptions());
+ CachedResult.Priority = Results[I].Priority;
+ CachedResult.Kind = Results[I].CursorKind;
+ CachedCompletionResults.push_back(CachedResult);
break;
-
+ }
+
case Result::RK_Keyword:
case Result::RK_Pattern:
// Ignore keywords and patterns; we don't care, since they are so
@@ -1287,8 +1367,9 @@ namespace {
public:
AugmentedCodeCompleteConsumer(ASTUnit &AST, CodeCompleteConsumer &Next,
- bool IncludeMacros, bool IncludeCodePatterns)
- : CodeCompleteConsumer(IncludeMacros, IncludeCodePatterns,
+ bool IncludeMacros, bool IncludeCodePatterns,
+ bool IncludeGlobals)
+ : CodeCompleteConsumer(IncludeMacros, IncludeCodePatterns, IncludeGlobals,
Next.isOutputBinary()), AST(AST), Next(Next)
{
// Compute the set of contexts in which we will look when we don't have
@@ -1387,6 +1468,8 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column,
FrontendOpts.ShowMacrosInCodeCompletion
= IncludeMacros && CachedCompletionResults.empty();
FrontendOpts.ShowCodePatternsInCodeCompletion = IncludeCodePatterns;
+ FrontendOpts.ShowGlobalSymbolsInCodeCompletion
+ = CachedCompletionResults.empty();
FrontendOpts.CodeCompletionAt.FileName = File;
FrontendOpts.CodeCompletionAt.Line = Line;
FrontendOpts.CodeCompletionAt.Column = Column;
@@ -1447,7 +1530,8 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column,
// code-completion results.
AugmentedCodeCompleteConsumer
AugmentedConsumer(*this, Consumer, FrontendOpts.ShowMacrosInCodeCompletion,
- FrontendOpts.ShowCodePatternsInCodeCompletion);
+ FrontendOpts.ShowCodePatternsInCodeCompletion,
+ FrontendOpts.ShowGlobalSymbolsInCodeCompletion);
Clang.setCodeCompletionConsumer(&AugmentedConsumer);
// If we have a precompiled preamble, try to use it. We only allow
diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp
index 06ec80589c..8e1dbcb9d2 100644
--- a/lib/Frontend/CompilerInstance.cpp
+++ b/lib/Frontend/CompilerInstance.cpp
@@ -328,6 +328,7 @@ void CompilerInstance::createCodeCompletionConsumer() {
getFrontendOpts().DebugCodeCompletionPrinter,
getFrontendOpts().ShowMacrosInCodeCompletion,
getFrontendOpts().ShowCodePatternsInCodeCompletion,
+ getFrontendOpts().ShowGlobalSymbolsInCodeCompletion,
llvm::outs()));
if (!CompletionConsumer)
return;
@@ -356,15 +357,18 @@ CompilerInstance::createCodeCompletionConsumer(Preprocessor &PP,
bool UseDebugPrinter,
bool ShowMacros,
bool ShowCodePatterns,
+ bool ShowGlobals,
llvm::raw_ostream &OS) {
if (EnableCodeCompletion(PP, Filename, Line, Column))
return 0;
// Set up the creation routine for code-completion.
if (UseDebugPrinter)
- return new PrintingCodeCompleteConsumer(ShowMacros, ShowCodePatterns, OS);
+ return new PrintingCodeCompleteConsumer(ShowMacros, ShowCodePatterns,
+ ShowGlobals, OS);
else
- return new CIndexCodeCompleteConsumer(ShowMacros, ShowCodePatterns, OS);
+ return new CIndexCodeCompleteConsumer(ShowMacros, ShowCodePatterns,
+ ShowGlobals, OS);
}
void CompilerInstance::createSema(bool CompleteTranslationUnit,
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index aa6888bd1d..5605f16dac 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -363,6 +363,8 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts,
Res.push_back("-code-completion-macros");
if (Opts.ShowCodePatternsInCodeCompletion)
Res.push_back("-code-completion-patterns");
+ if (!Opts.ShowGlobalSymbolsInCodeCompletion)
+ Res.push_back("-no-code-completion-globals");
if (Opts.ShowStats)
Res.push_back("-print-stats");
if (Opts.ShowTimers)
@@ -1047,6 +1049,8 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
Opts.ShowMacrosInCodeCompletion = Args.hasArg(OPT_code_completion_macros);
Opts.ShowCodePatternsInCodeCompletion
= Args.hasArg(OPT_code_completion_patterns);
+ Opts.ShowGlobalSymbolsInCodeCompletion
+ = !Args.hasArg(OPT_no_code_completion_globals);
Opts.ShowStats = Args.hasArg(OPT_print_stats);
Opts.ShowTimers = Args.hasArg(OPT_ftime_report);
Opts.ShowVersion = Args.hasArg(OPT_version);
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index 31185683a1..599a10fd90 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -2308,7 +2308,8 @@ void Sema::CodeCompleteOrdinaryName(Scope *S,
}
CodeCompletionDeclConsumer Consumer(Results, CurContext);
- LookupVisibleDecls(S, LookupOrdinaryName, Consumer);
+ LookupVisibleDecls(S, LookupOrdinaryName, Consumer,
+ CodeCompleter->includeGlobals());
Results.EnterNewScope();
AddOrdinaryNameResults(CompletionContext, S, *this, Results);
@@ -2340,7 +2341,8 @@ void Sema::CodeCompleteExpression(Scope *S, QualType T,
Results.setPreferredType(T.getNonReferenceType());
CodeCompletionDeclConsumer Consumer(Results, CurContext);
- LookupVisibleDecls(S, LookupOrdinaryName, Consumer);
+ LookupVisibleDecls(S, LookupOrdinaryName, Consumer,
+ CodeCompleter->includeGlobals());
Results.EnterNewScope();
AddOrdinaryNameResults(PCC_Expression, S, *this, Results);
@@ -2432,7 +2434,8 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE,
// Access to a C/C++ class, struct, or union.
Results.allowNestedNameSpecifiers();
CodeCompletionDeclConsumer Consumer(Results, CurContext);
- LookupVisibleDecls(Record->getDecl(), LookupMemberName, Consumer);
+ LookupVisibleDecls(Record->getDecl(), LookupMemberName, Consumer,
+ CodeCompleter->includeGlobals());
if (getLangOptions().CPlusPlus) {
if (!Results.empty()) {
@@ -2480,7 +2483,8 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE,
if (Class) {
CodeCompletionDeclConsumer Consumer(Results, CurContext);
Results.setFilter(&ResultBuilder::IsObjCIvar);
- LookupVisibleDecls(Class, LookupMemberName, Consumer);
+ LookupVisibleDecls(Class, LookupMemberName, Consumer,
+ CodeCompleter->includeGlobals());
}
}
@@ -2530,11 +2534,14 @@ void Sema::CodeCompleteTag(Scope *S, unsigned TagSpec) {
// First pass: look for tags.
Results.setFilter(Filter);
- LookupVisibleDecls(S, LookupTagName, Consumer);
+ LookupVisibleDecls(S, LookupTagName, Consumer,
+ CodeCompleter->includeGlobals());
- // Second pass: look for nested name specifiers.
- Results.setFilter(&ResultBuilder::IsNestedNameSpecifier);
- LookupVisibleDecls(S, LookupNestedNameSpecifierName, Consumer);
+ if (CodeCompleter->includeGlobals()) {
+ // Second pass: look for nested name specifiers.
+ Results.setFilter(&ResultBuilder::IsNestedNameSpecifier);
+ LookupVisibleDecls(S, LookupNestedNameSpecifierName, Consumer);
+ }
HandleCodeCompleteResults(this, CodeCompleter, ContextKind,
Results.data(),Results.size());
@@ -2836,7 +2843,8 @@ void Sema::CodeCompleteUsing(Scope *S) {
// After "using", we can see anything that would start a
// nested-name-specifier.
CodeCompletionDeclConsumer Consumer(Results, CurContext);
- LookupVisibleDecls(S, LookupOrdinaryName, Consumer);
+ LookupVisibleDecls(S, LookupOrdinaryName, Consumer,
+ CodeCompleter->includeGlobals());
Results.ExitScope();
HandleCodeCompleteResults(this, CodeCompleter,
@@ -2853,10 +2861,11 @@ void Sema::CodeCompleteUsingDirective(Scope *S) {
ResultBuilder Results(*this, &ResultBuilder::IsNamespaceOrAlias);
Results.EnterNewScope();
CodeCompletionDeclConsumer Consumer(Results, CurContext);
- LookupVisibleDecls(S, LookupOrdinaryName, Consumer);
+ LookupVisibleDecls(S, LookupOrdinaryName, Consumer,
+ CodeCompleter->includeGlobals());
Results.ExitScope();
HandleCodeCompleteResults(this, CodeCompleter,
- CodeCompletionContext::CCC_Other,
+ CodeCompletionContext::CCC_Namespace,
Results.data(),Results.size());
}
@@ -2903,9 +2912,10 @@ void Sema::CodeCompleteNamespaceAliasDecl(Scope *S) {
// After "namespace", we expect to see a namespace or alias.
ResultBuilder Results(*this, &ResultBuilder::IsNamespaceOrAlias);
CodeCompletionDeclConsumer Consumer(Results, CurContext);
- LookupVisibleDecls(S, LookupOrdinaryName, Consumer);
+ LookupVisibleDecls(S, LookupOrdinaryName, Consumer,
+ CodeCompleter->includeGlobals());
HandleCodeCompleteResults(this, CodeCompleter,
- CodeCompletionContext::CCC_Other,
+ CodeCompletionContext::CCC_Namespace,
Results.data(),Results.size());
}
@@ -2926,14 +2936,15 @@ void Sema::CodeCompleteOperatorName(Scope *S) {
// Add any type names visible from the current scope
Results.allowNestedNameSpecifiers();
CodeCompletionDeclConsumer Consumer(Results, CurContext);
- LookupVisibleDecls(S, LookupOrdinaryName, Consumer);
+ LookupVisibleDecls(S, LookupOrdinaryName, Consumer,
+ CodeCompleter->includeGlobals());
// Add any type specifiers
AddTypeSpecifierResults(getLangOptions(), Results);
Results.ExitScope();
HandleCodeCompleteResults(this, CodeCompleter,
- CodeCompletionContext::CCC_Other,
+ CodeCompletionContext::CCC_Type,
Results.data(),Results.size());
}
@@ -3514,7 +3525,8 @@ void Sema::CodeCompleteObjCMessageReceiver(Scope *S) {
Results.setFilter(&ResultBuilder::IsObjCMessageReceiver);
CodeCompletionDeclConsumer Consumer(Results, CurContext);
Results.EnterNewScope();
- LookupVisibleDecls(S, LookupOrdinaryName, Consumer);
+ LookupVisibleDecls(S, LookupOrdinaryName, Consumer,
+ CodeCompleter->includeGlobals());
// If we are in an Objective-C method inside a class that has a superclass,
// add "super" as an option.
@@ -4341,13 +4353,12 @@ void Sema::GatherGlobalCodeCompletions(
llvm::SmallVectorImpl<CodeCompleteConsumer::Result> &Results) {
ResultBuilder Builder(*this);
-#if 0
- // FIXME: We need a name lookup that means "look for everything",
- CodeCompletionDeclConsumer Consumer(Builder,
- Context.getTranslationUnitDecl());
- LookupVisibleDecls(Context.getTranslationUnitDecl(), LookupOrdinaryName,
- Consumer);
-#endif
+ if (!CodeCompleter || CodeCompleter->includeGlobals()) {
+ CodeCompletionDeclConsumer Consumer(Builder,
+ Context.getTranslationUnitDecl());
+ LookupVisibleDecls(Context.getTranslationUnitDecl(), LookupAnyName,
+ Consumer);
+ }
if (!CodeCompleter || CodeCompleter->includeMacros())
AddMacroResults(PP, Builder);
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index 1ffea89acd..994b633db8 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -254,6 +254,12 @@ static inline unsigned getIDNS(Sema::LookupNameKind NameKind,
case Sema::LookupObjCProtocolName:
IDNS = Decl::IDNS_ObjCProtocol;
break;
+
+ case Sema::LookupAnyName:
+ IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Member
+ | Decl::IDNS_Using | Decl::IDNS_Namespace | Decl::IDNS_ObjCProtocol
+ | Decl::IDNS_Type;
+ break;
}
return IDNS;
}
@@ -1199,6 +1205,17 @@ static bool LookupQualifiedNameInUsingDirectives(Sema &S, LookupResult &R,
return Found;
}
+/// \brief Callback that looks for any member of a class with the given name.
+static bool LookupAnyMember(const CXXBaseSpecifier *Specifier,
+ CXXBasePath &Path,
+ void *Name) {
+ RecordDecl *BaseRecord = Specifier->getType()->getAs<RecordType>()->getDecl();
+
+ DeclarationName N = DeclarationName::getFromOpaquePtr(Name);
+ Path.Decls = BaseRecord->lookup(N);
+ return Path.Decls.first != Path.Decls.second;
+}
+
/// \brief Perform qualified name lookup into a given context.
///
/// Qualified name lookup (C++ [basic.lookup.qual]) is used to find
@@ -1294,6 +1311,10 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
BaseCallback = &CXXRecordDecl::FindTagMember;
break;
+ case LookupAnyName:
+ BaseCallback = &LookupAnyMember;
+ break;
+
case LookupUsingDeclName:
// This lookup is for redeclarations only.
@@ -2223,6 +2244,10 @@ public:
return !VisitedContexts.insert(Ctx);
}
+ bool alreadyVisitedContext(DeclContext *Ctx) {
+ return VisitedContexts.count(Ctx);
+ }
+
/// \brief Determine whether the given declaration is hidden in the
/// current scope.
///
@@ -2503,7 +2528,9 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result,
if (!S)
return;
- if (!S->getEntity() || !S->getParent() ||
+ if (!S->getEntity() ||
+ (!S->getParent() &&
+ !Visited.alreadyVisitedContext((DeclContext *)S->getEntity())) ||
((DeclContext *)S->getEntity())->isFunctionOrMethod()) {
// Walk through the declarations in this Scope.
for (Scope::decl_iterator D = S->decl_begin(), DEnd = S->decl_end();
@@ -2581,7 +2608,8 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result,
}
void Sema::LookupVisibleDecls(Scope *S, LookupNameKind Kind,
- VisibleDeclConsumer &Consumer) {
+ VisibleDeclConsumer &Consumer,
+ bool IncludeGlobalScope) {
// Determine the set of using directives available during
// unqualified name lookup.
Scope *Initial = S;
@@ -2598,14 +2626,19 @@ void Sema::LookupVisibleDecls(Scope *S, LookupNameKind Kind,
// Look for visible declarations.
LookupResult Result(*this, DeclarationName(), SourceLocation(), Kind);
VisibleDeclsRecord Visited;
+ if (!IncludeGlobalScope)
+ Visited.visitedContext(Context.getTranslationUnitDecl());
ShadowContextRAII Shadow(Visited);
::LookupVisibleDecls(Initial, Result, UDirs, Consumer, Visited);
}
void Sema::LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind,
- VisibleDeclConsumer &Consumer) {
+ VisibleDeclConsumer &Consumer,
+ bool IncludeGlobalScope) {
LookupResult Result(*this, DeclarationName(), SourceLocation(), Kind);
VisibleDeclsRecord Visited;
+ if (!IncludeGlobalScope)
+ Visited.visitedContext(Context.getTranslationUnitDecl());
ShadowContextRAII Shadow(Visited);
::LookupVisibleDecls(Ctx, Result, /*QualifiedNameLookup=*/true,
/*InBaseClass=*/false, Consumer, Visited);