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
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index e6bae6b..8d49d4e 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -88,6 +88,79 @@
   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 @@
   // 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 @@
     
   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 @@
   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 @@
   // 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 06ec805..8e1dbcb 100644
--- a/lib/Frontend/CompilerInstance.cpp
+++ b/lib/Frontend/CompilerInstance.cpp
@@ -328,6 +328,7 @@
                                    getFrontendOpts().DebugCodeCompletionPrinter,
                                    getFrontendOpts().ShowMacrosInCodeCompletion,
                              getFrontendOpts().ShowCodePatternsInCodeCompletion,
+                           getFrontendOpts().ShowGlobalSymbolsInCodeCompletion,
                                    llvm::outs()));
     if (!CompletionConsumer)
       return;
@@ -356,15 +357,18 @@
                                                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 aa6888b..5605f16 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -363,6 +363,8 @@
     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 @@
   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);