Declarations lookup replaced with CXXFinalOverriderMap usage. Added test case.

  Now it doesn't use methods names and handles diamond inheritance almost 
correctly. The only issue is that method implemented in each class in diamond 
inheritance will be added 2 times, once per each branch.

Hi rsmith,

http://llvm-reviews.chandlerc.com/D622

CHANGE SINCE LAST DIFF
  http://llvm-reviews.chandlerc.com/D622?vs=1505&id=1764#toc

Files:
  lib/Sema/SemaCodeComplete.cpp
  include/clang/Sema/CodeCompleteConsumer.h

Index: lib/Sema/SemaCodeComplete.cpp
===================================================================
--- lib/Sema/SemaCodeComplete.cpp
+++ lib/Sema/SemaCodeComplete.cpp
@@ -11,6 +11,7 @@
 //
 
//===----------------------------------------------------------------------===//
 #include "clang/Sema/SemaInternal.h"
+#include "clang/AST/CXXInheritance.h"
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/ExprCXX.h"
 #include "clang/AST/ExprObjC.h"
@@ -303,7 +304,7 @@
     /// \param InBaseClass whether the result was found in a base
     /// class of the searched context.
     void AddResult(Result R, DeclContext *CurContext, NamedDecl *Hiding,
-                   bool InBaseClass);
+                   bool InBaseClass, bool WillOverridePureVirtual);
     
     /// \brief Add a new non-declaration result to this result set.
     void AddResult(Result R);
@@ -930,7 +931,8 @@
 }
 
 void ResultBuilder::AddResult(Result R, DeclContext *CurContext, 
-                              NamedDecl *Hiding, bool InBaseClass = false) {
+                              NamedDecl *Hiding, bool InBaseClass = false,
+                              bool WillOverridePureVirtual = false) {
   if (R.Kind != Result::RK_Declaration) {
     // For non-declaration results, just add the result.
     Results.push_back(R);
@@ -988,6 +990,9 @@
   // Adjust the priority if this result comes from a base class.
   if (InBaseClass)
     R.Priority += CCD_InBaseClass;
+  // Adjust the priority if this result overrides pure virtual method.
+  if (WillOverridePureVirtual)
+    R.Priority /= CCF_OverridePureVirtual;
   
   AdjustResultPriorityForDecl(R);
   
@@ -3215,6 +3220,9 @@
                             Results.data(),Results.size());
 }
 
+static void AddOverridableMethodsCompletions(Sema &SemaRef, Scope *S,
+                                             ResultBuilder &Results);
+
 void Sema::CodeCompleteOrdinaryName(Scope *S, 
                                     ParserCompletionContext CompletionContext) 
{
   ResultBuilder Results(*this, CodeCompleter->getAllocator(),
@@ -3227,7 +3235,6 @@
   // only allowed where we can have an expression.
   switch (CompletionContext) {
   case PCC_Namespace:
-  case PCC_Class:
   case PCC_ObjCInterface:
   case PCC_ObjCImplementation:
   case PCC_ObjCInstanceVariableList:
@@ -3238,6 +3245,13 @@
     Results.setFilter(&ResultBuilder::IsOrdinaryNonValueName);
     break;
 
+  case PCC_Class: {
+    if (getLangOpts().CPlusPlus)
+      AddOverridableMethodsCompletions(*this, S, Results);
+    Results.setFilter(&ResultBuilder::IsOrdinaryNonValueName);
+    break;
+  }
+
   case PCC_Statement:
   case PCC_ParenthesizedExpression:
   case PCC_Expression:
@@ -5407,6 +5421,75 @@
   return PreferredType;
 }
 
+static void AddOverridableMethodsCompletions(Sema &SemaRef, Scope *S,
+                                             ResultBuilder &Results)
+{
+  CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>((DeclContext 
*)S->getEntity());
+  CXXFinalOverriderMap Map;
+  Record->getFinalOverriders(Map);
+
+  // Discard base method if it's final overrider have 'final' attribute
+  llvm::SmallPtrSet<const CXXMethodDecl *, 8> DiscardedMethods;
+  for (CXXFinalOverriderMap::const_iterator I = Map.begin(),
+       E = Map.end(); I != E; ++I) {
+    if (isa<CXXDestructorDecl>(I->first))
+      continue;
+    const OverridingMethods& Methods = I->second;
+
+    for (OverridingMethods::const_iterator OI = Methods.begin(),
+                                        EndOI = Methods.end();
+         OI != EndOI; ++OI) {
+      const CXXMethodDecl *Method = OI->second.front().Method;
+      if (Method->getAttr<FinalAttr>()) {
+        DiscardedMethods.insert(I->first);
+        break;
+      }
+    }
+  }
+
+  // Discard final overrider if it's base method was discarded
+  llvm::SmallPtrSet<const CXXMethodDecl *, 8> DiscardedOverriders;
+  for (CXXFinalOverriderMap::const_iterator I = Map.begin(),
+       E = Map.end(); I != E; ++I) {
+    const OverridingMethods& Methods = I->second;
+    if (0 == DiscardedMethods.count(I->first))
+      continue;
+
+    for (OverridingMethods::const_iterator OI = Methods.begin(),
+                                        EndOI = Methods.end();
+         OI != EndOI; ++OI) {
+      const CXXMethodDecl *Method = OI->second.front().Method;
+      DiscardedOverriders.insert(Method);
+    }
+  }
+
+  // Finally, add completion for each base method that was not discarded
+  // and have no discarded final overriders.
+  for (CXXFinalOverriderMap::const_iterator I = Map.begin(),
+       E = Map.end(); I != E; ++I) {
+    if (isa<CXXDestructorDecl>(I->first) || DiscardedMethods.count(I->first))
+      continue;
+    const OverridingMethods& Methods = I->second;
+
+    CXXMethodDecl *MD = 0;
+    for (OverridingMethods::const_iterator OI = Methods.begin(),
+                                        EndOI = Methods.end();
+         !MD && OI != EndOI; ++OI) {
+      MD = OI->second.front().Method;
+      if (DiscardedOverriders.count(MD) || MD->getParent() == Record ||
+          MD != I->first)
+        MD = 0;
+    }
+    if (!MD)
+      continue;
+
+    bool Accessible = SemaRef.IsSimplyAccessible(MD, Record->getDeclContext());
+    ResultBuilder::Result Result2(MD, CCP_MemberDeclaration, 0,
+                                  false, Accessible);
+    Results.AddResult(Result2, Record, 0, true, MD->isPure());
+  }
+}
+
 static void AddClassMessageCompletions(Sema &SemaRef, Scope *S, 
                                        ParsedType Receiver,
                                        IdentifierInfo **SelIdents,
Index: include/clang/Sema/CodeCompleteConsumer.h
===================================================================
--- include/clang/Sema/CodeCompleteConsumer.h
+++ include/clang/Sema/CodeCompleteConsumer.h
@@ -99,7 +99,10 @@
   /// \brief Divide by this factor when a code-completion result's type is
   /// similar to the type we expect (e.g., both arithmetic types, both
   /// Objective-C object pointer types).
-  CCF_SimilarTypeMatch = 2
+  CCF_SimilarTypeMatch = 2,
+  /// \brief Divide by this factor when a code-completion will override
+  /// pure virtual method rather than just virtual
+  CCF_OverridePureVirtual = 2
 };
 
 /// \brief A simplified classification of types used when determining
Index: lib/Sema/SemaCodeComplete.cpp
===================================================================
--- lib/Sema/SemaCodeComplete.cpp
+++ lib/Sema/SemaCodeComplete.cpp
@@ -11,6 +11,7 @@
 //
 //===----------------------------------------------------------------------===//
 #include "clang/Sema/SemaInternal.h"
+#include "clang/AST/CXXInheritance.h"
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/ExprCXX.h"
 #include "clang/AST/ExprObjC.h"
@@ -303,7 +304,7 @@
     /// \param InBaseClass whether the result was found in a base
     /// class of the searched context.
     void AddResult(Result R, DeclContext *CurContext, NamedDecl *Hiding,
-                   bool InBaseClass);
+                   bool InBaseClass, bool WillOverridePureVirtual);
     
     /// \brief Add a new non-declaration result to this result set.
     void AddResult(Result R);
@@ -930,7 +931,8 @@
 }
 
 void ResultBuilder::AddResult(Result R, DeclContext *CurContext, 
-                              NamedDecl *Hiding, bool InBaseClass = false) {
+                              NamedDecl *Hiding, bool InBaseClass = false,
+                              bool WillOverridePureVirtual = false) {
   if (R.Kind != Result::RK_Declaration) {
     // For non-declaration results, just add the result.
     Results.push_back(R);
@@ -988,6 +990,9 @@
   // Adjust the priority if this result comes from a base class.
   if (InBaseClass)
     R.Priority += CCD_InBaseClass;
+  // Adjust the priority if this result overrides pure virtual method.
+  if (WillOverridePureVirtual)
+    R.Priority /= CCF_OverridePureVirtual;
   
   AdjustResultPriorityForDecl(R);
   
@@ -3215,6 +3220,9 @@
                             Results.data(),Results.size());
 }
 
+static void AddOverridableMethodsCompletions(Sema &SemaRef, Scope *S,
+                                             ResultBuilder &Results);
+
 void Sema::CodeCompleteOrdinaryName(Scope *S, 
                                     ParserCompletionContext CompletionContext) {
   ResultBuilder Results(*this, CodeCompleter->getAllocator(),
@@ -3227,7 +3235,6 @@
   // only allowed where we can have an expression.
   switch (CompletionContext) {
   case PCC_Namespace:
-  case PCC_Class:
   case PCC_ObjCInterface:
   case PCC_ObjCImplementation:
   case PCC_ObjCInstanceVariableList:
@@ -3238,6 +3245,13 @@
     Results.setFilter(&ResultBuilder::IsOrdinaryNonValueName);
     break;
 
+  case PCC_Class: {
+    if (getLangOpts().CPlusPlus)
+      AddOverridableMethodsCompletions(*this, S, Results);
+    Results.setFilter(&ResultBuilder::IsOrdinaryNonValueName);
+    break;
+  }
+
   case PCC_Statement:
   case PCC_ParenthesizedExpression:
   case PCC_Expression:
@@ -5407,6 +5421,75 @@
   return PreferredType;
 }
 
+static void AddOverridableMethodsCompletions(Sema &SemaRef, Scope *S,
+                                             ResultBuilder &Results)
+{
+  CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>((DeclContext *)S->getEntity());
+  CXXFinalOverriderMap Map;
+  Record->getFinalOverriders(Map);
+
+  // Discard base method if it's final overrider have 'final' attribute
+  llvm::SmallPtrSet<const CXXMethodDecl *, 8> DiscardedMethods;
+  for (CXXFinalOverriderMap::const_iterator I = Map.begin(),
+       E = Map.end(); I != E; ++I) {
+    if (isa<CXXDestructorDecl>(I->first))
+      continue;
+    const OverridingMethods& Methods = I->second;
+
+    for (OverridingMethods::const_iterator OI = Methods.begin(),
+                                        EndOI = Methods.end();
+         OI != EndOI; ++OI) {
+      const CXXMethodDecl *Method = OI->second.front().Method;
+      if (Method->getAttr<FinalAttr>()) {
+        DiscardedMethods.insert(I->first);
+        break;
+      }
+    }
+  }
+
+  // Discard final overrider if it's base method was discarded
+  llvm::SmallPtrSet<const CXXMethodDecl *, 8> DiscardedOverriders;
+  for (CXXFinalOverriderMap::const_iterator I = Map.begin(),
+       E = Map.end(); I != E; ++I) {
+    const OverridingMethods& Methods = I->second;
+    if (0 == DiscardedMethods.count(I->first))
+      continue;
+
+    for (OverridingMethods::const_iterator OI = Methods.begin(),
+                                        EndOI = Methods.end();
+         OI != EndOI; ++OI) {
+      const CXXMethodDecl *Method = OI->second.front().Method;
+      DiscardedOverriders.insert(Method);
+    }
+  }
+
+  // Finally, add completion for each base method that was not discarded
+  // and have no discarded final overriders.
+  for (CXXFinalOverriderMap::const_iterator I = Map.begin(),
+       E = Map.end(); I != E; ++I) {
+    if (isa<CXXDestructorDecl>(I->first) || DiscardedMethods.count(I->first))
+      continue;
+    const OverridingMethods& Methods = I->second;
+
+    CXXMethodDecl *MD = 0;
+    for (OverridingMethods::const_iterator OI = Methods.begin(),
+                                        EndOI = Methods.end();
+         !MD && OI != EndOI; ++OI) {
+      MD = OI->second.front().Method;
+      if (DiscardedOverriders.count(MD) || MD->getParent() == Record ||
+          MD != I->first)
+        MD = 0;
+    }
+    if (!MD)
+      continue;
+
+    bool Accessible = SemaRef.IsSimplyAccessible(MD, Record->getDeclContext());
+    ResultBuilder::Result Result2(MD, CCP_MemberDeclaration, 0,
+                                  false, Accessible);
+    Results.AddResult(Result2, Record, 0, true, MD->isPure());
+  }
+}
+
 static void AddClassMessageCompletions(Sema &SemaRef, Scope *S, 
                                        ParsedType Receiver,
                                        IdentifierInfo **SelIdents,
Index: include/clang/Sema/CodeCompleteConsumer.h
===================================================================
--- include/clang/Sema/CodeCompleteConsumer.h
+++ include/clang/Sema/CodeCompleteConsumer.h
@@ -99,7 +99,10 @@
   /// \brief Divide by this factor when a code-completion result's type is
   /// similar to the type we expect (e.g., both arithmetic types, both
   /// Objective-C object pointer types).
-  CCF_SimilarTypeMatch = 2
+  CCF_SimilarTypeMatch = 2,
+  /// \brief Divide by this factor when a code-completion will override
+  /// pure virtual method rather than just virtual
+  CCF_OverridePureVirtual = 2
 };
 
 /// \brief A simplified classification of types used when determining
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to