Tweak the code-completion results ranking and formation, so that
members found in base classes have the same ranking as members found
in derived classes. However, we will introduce an informative note for
members found in base classes, showing (as a nested-name-specifier)
the qualification to name the base class, to make it clear which
members are from bases.
 

llvm-svn: 82586
diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp
index b19fda2..f57480e 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -197,8 +197,8 @@
   
   // Look through using declarations.
   if (UsingDecl *Using = dyn_cast<UsingDecl>(R.Declaration))
-    return MaybeAddResult(Result(Using->getTargetDecl(), R.Rank, R.Qualifier),
-                          CurContext);
+    MaybeAddResult(Result(Using->getTargetDecl(), R.Rank, R.Qualifier),
+                   CurContext);
   
   // Handle each declaration in an overload set separately.
   if (OverloadedFunctionDecl *Ovl 
@@ -281,6 +281,7 @@
                                  I->second.first)) {
         // Note that this result was hidden.
         R.Hidden = true;
+        R.QualifierIsInformative = false;
         
         if (!R.Qualifier)
           R.Qualifier = getRequiredQualification(SemaRef.Context, 
@@ -300,6 +301,18 @@
   if (!AllDeclsFound.insert(CanonDecl))
     return;
   
+  // If this result is supposed to have an informative qualifier, add one.
+  if (R.QualifierIsInformative && !R.Qualifier) {
+    DeclContext *Ctx = R.Declaration->getDeclContext();
+    if (NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(Ctx))
+      R.Qualifier = NestedNameSpecifier::Create(SemaRef.Context, 0, Namespace);
+    else if (TagDecl *Tag = dyn_cast<TagDecl>(Ctx))
+      R.Qualifier = NestedNameSpecifier::Create(SemaRef.Context, 0, false, 
+                             SemaRef.Context.getTypeDeclType(Tag).getTypePtr());
+    else
+      R.QualifierIsInformative = false;
+  }
+  
   // Insert this result into the set of results and into the current shadow
   // map.
   SMap.insert(std::make_pair(R.Declaration->getDeclName(),
@@ -398,9 +411,7 @@
 ///
 /// \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 Rank the rank given to results in this declaration context.
 ///
 /// \param Visited the set of declaration contexts that have already been
 /// visited. Declaration contexts will only be visited once.
@@ -408,18 +419,22 @@
 /// \param Results the result set that will be extended with any results
 /// found within this declaration context (and, for a C++ class, its bases).
 ///
+/// \param InBaseClass whether we are in a base class.
+///
 /// \returns the next higher rank value, after considering all of the
 /// names within this declaration context.
 static unsigned CollectMemberLookupResults(DeclContext *Ctx, 
-                                           unsigned InitialRank,
+                                           unsigned Rank,
                                            DeclContext *CurContext,
                                  llvm::SmallPtrSet<DeclContext *, 16> &Visited,
-                                           ResultBuilder &Results) {
+                                           ResultBuilder &Results,
+                                           bool InBaseClass = false) {
   // Make sure we don't visit the same context twice.
   if (!Visited.insert(Ctx->getPrimaryContext()))
-    return InitialRank;
+    return Rank;
   
   // Enumerate all of the results in this context.
+  typedef CodeCompleteConsumer::Result Result;
   Results.EnterNewScope();
   for (DeclContext *CurCtx = Ctx->getPrimaryContext(); CurCtx; 
        CurCtx = CurCtx->getNextContext()) {
@@ -427,13 +442,11 @@
          DEnd = CurCtx->decls_end();
          D != DEnd; ++D) {
       if (NamedDecl *ND = dyn_cast<NamedDecl>(*D))
-        Results.MaybeAddResult(CodeCompleteConsumer::Result(ND, InitialRank),
-                               CurContext);
+        Results.MaybeAddResult(Result(ND, Rank, 0, InBaseClass), CurContext);
     }
   }
   
   // 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();
@@ -468,19 +481,15 @@
       //   c->A::member
       
       // Collect results from this base class (and its bases).
-      NextRank = std::max(NextRank, 
-                          CollectMemberLookupResults(Record->getDecl(), 
-                                                     InitialRank + 1,
-                                                     CurContext,
-                                                     Visited,
-                                                     Results));
+      CollectMemberLookupResults(Record->getDecl(), Rank, CurContext, Visited,
+                                 Results, /*InBaseClass=*/true);
     }
   }
   
   // FIXME: Look into base classes in Objective-C!
   
   Results.ExitScope();
-  return NextRank;
+  return Rank + 1;
 }
 
 /// \brief Collect the results of searching for members within the given
@@ -735,6 +744,7 @@
 /// provided nested-name-specifier is non-NULL.
 void AddQualifierToCompletionString(CodeCompletionString *Result, 
                                     NestedNameSpecifier *Qualifier, 
+                                    bool QualifierIsInformative,
                                     ASTContext &Context) {
   if (!Qualifier)
     return;
@@ -744,7 +754,10 @@
     llvm::raw_string_ostream OS(PrintedNNS);
     Qualifier->print(OS, Context.PrintingPolicy);
   }
-  Result->AddTextChunk(PrintedNNS.c_str());
+  if (QualifierIsInformative)
+    Result->AddInformativeChunk(PrintedNNS.c_str());
+  else
+    Result->AddTextChunk(PrintedNNS.c_str());
 }
 
 /// \brief If possible, create a new code completion string for the given
@@ -762,7 +775,8 @@
   
   if (FunctionDecl *Function = dyn_cast<FunctionDecl>(ND)) {
     CodeCompletionString *Result = new CodeCompletionString;
-    AddQualifierToCompletionString(Result, Qualifier, S.Context);
+    AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, 
+                                   S.Context);
     Result->AddTextChunk(Function->getNameAsString().c_str());
     Result->AddTextChunk("(");
     AddFunctionParameterChunks(S.Context, Function, Result);
@@ -772,7 +786,8 @@
   
   if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(ND)) {
     CodeCompletionString *Result = new CodeCompletionString;
-    AddQualifierToCompletionString(Result, Qualifier, S.Context);
+    AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, 
+                                   S.Context);
     FunctionDecl *Function = FunTmpl->getTemplatedDecl();
     Result->AddTextChunk(Function->getNameAsString().c_str());
     
@@ -825,7 +840,8 @@
   
   if (TemplateDecl *Template = dyn_cast<TemplateDecl>(ND)) {
     CodeCompletionString *Result = new CodeCompletionString;
-    AddQualifierToCompletionString(Result, Qualifier, S.Context);
+    AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, 
+                                   S.Context);
     Result->AddTextChunk(Template->getNameAsString().c_str());
     Result->AddTextChunk("<");
     AddTemplateParameterChunks(S.Context, Template, Result);
@@ -835,7 +851,8 @@
   
   if (Qualifier) {
     CodeCompletionString *Result = new CodeCompletionString;
-    AddQualifierToCompletionString(Result, Qualifier, S.Context);
+    AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, 
+                                   S.Context);
     Result->AddTextChunk(ND->getNameAsString().c_str());
     return Result;
   }