[PATCH] Added code-completion results to override virtual methods from base class

Sergey Shambir sergey.shambir.auto at gmail.com
Wed Apr 24 13:02:38 PDT 2013


  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
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D622.2.patch
Type: text/x-patch
Size: 6318 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20130424/55464071/attachment.bin>


More information about the cfe-commits mailing list