]> granicus.if.org Git - clang/commitdiff
When code-completing a potential call to a C++ non-static member
authorDouglas Gregor <dgregor@apple.com>
Thu, 26 Aug 2010 16:36:48 +0000 (16:36 +0000)
committerDouglas Gregor <dgregor@apple.com>
Thu, 26 Aug 2010 16:36:48 +0000 (16:36 +0000)
function, take into account the qualifiers on the object argument
(e.g., what will become "this"), filtering around uncallable member
functions and giving a slight priority boost to those with
exactly-matching qualifiers.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@112193 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/ASTContext.h
include/clang/AST/Type.h
include/clang/Sema/CodeCompleteConsumer.h
lib/Sema/SemaCodeComplete.cpp
test/Index/complete-memfunc-cvquals.cpp [new file with mode: 0644]

index fdf2d52bbbed4f486f455f3273d59ba8eb7105ed..20c8d1f41d0cd39352fc41f03050d6d59ab8b28b 100644 (file)
@@ -1073,8 +1073,6 @@ public:
 
   bool UnwrapSimilarPointerTypes(QualType &T1, QualType &T2);
   
-  /// \brief Retrieves the "canonical" declaration of
-
   /// \brief Retrieves the "canonical" nested name specifier for a
   /// given nested name specifier.
   ///
index 5a69932051b2c8600fb9971c2072a32b4a4d8597..819d7d24a53a10bce97df17afb030e31b22719fc 100644 (file)
@@ -289,7 +289,18 @@ public:
     L += R;
     return L;
   }
+  
+  Qualifiers &operator-=(Qualifiers R) {
+    Mask = Mask & ~(R.Mask);
+    return *this;
+  }
 
+  /// \brief Compute the difference between two qualifier sets.
+  friend Qualifiers operator-(Qualifiers L, Qualifiers R) {
+    L -= R;
+    return L;
+  }
+  
   std::string getAsString() const;
   std::string getAsString(const PrintingPolicy &Policy) const {
     std::string Buffer;
index 55bd576f9651e31bbd61f063b4fc4e8d84d9790d..27cda88cb2dd3ae68f24ec02ef2936585747ae07 100644 (file)
@@ -55,7 +55,7 @@ enum {
   CCP_Unlikely = 80
 };
 
-/// \brief Priority value deltas that are applied to code-completion results
+/// \brief Priority value deltas that are added to code-completion results
 /// based on the context of the result.
 enum {
   /// \brief The result is in a base class.
@@ -64,7 +64,10 @@ enum {
   ///
   /// Since everything converts to "void", we don't give as drastic an 
   /// adjustment for matching void.
-  CCD_VoidMatch = -5
+  CCD_VoidMatch = -5,
+  /// \brief The result is a C++ non-static member function whose qualifiers
+  /// exactly match the object type on which the member function can be called.
+  CCD_ObjectQualifierMatch = -1
 };
 
 /// \brief Priority value factors by which we will divide or multiply the
index b75a7d05bba9946a7d7595e267f5086c4d3ef25f..392152630d5d5f180bb93dd97c7b46440fa186c1 100644 (file)
@@ -136,11 +136,19 @@ namespace {
     /// different levels of, e.g., the inheritance hierarchy.
     std::list<ShadowMap> ShadowMaps;
     
+    /// \brief If we're potentially referring to a C++ member function, the set
+    /// of qualifiers applied to the object type.
+    Qualifiers ObjectTypeQualifiers;
+    
+    /// \brief Whether the \p ObjectTypeQualifiers field is active.
+    bool HasObjectTypeQualifiers;
+    
     void AdjustResultPriorityForPreferredType(Result &R);
 
   public:
     explicit ResultBuilder(Sema &SemaRef, LookupFilter Filter = 0)
-      : SemaRef(SemaRef), Filter(Filter), AllowNestedNameSpecifiers(false) { }
+      : SemaRef(SemaRef), Filter(Filter), AllowNestedNameSpecifiers(false),
+        HasObjectTypeQualifiers(false) { }
     
     /// \brief Whether we should include code patterns in the completion
     /// results.
@@ -167,6 +175,18 @@ namespace {
       PreferredType = SemaRef.Context.getCanonicalType(T); 
     }
     
+    /// \brief Set the cv-qualifiers on the object type, for us in filtering
+    /// calls to member functions.
+    ///
+    /// When there are qualifiers in this set, they will be used to filter
+    /// out member functions that aren't available (because there will be a 
+    /// cv-qualifier mismatch) or prefer functions with an exact qualifier
+    /// match.
+    void setObjectTypeQualifiers(Qualifiers Quals) {
+      ObjectTypeQualifiers = Quals;
+      HasObjectTypeQualifiers = true;
+    }
+    
     /// \brief Specify whether nested-name-specifiers are allowed.
     void allowNestedNameSpecifiers(bool Allow = true) {
       AllowNestedNameSpecifiers = Allow;
@@ -770,6 +790,20 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext,
   if (!PreferredType.isNull())
     AdjustResultPriorityForPreferredType(R);
   
+  if (HasObjectTypeQualifiers)
+    if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(R.Declaration))
+      if (Method->isInstance()) {
+        Qualifiers MethodQuals
+                        = Qualifiers::fromCVRMask(Method->getTypeQualifiers());
+        if (ObjectTypeQualifiers == MethodQuals)
+          R.Priority += CCD_ObjectQualifierMatch;
+        else if (ObjectTypeQualifiers - MethodQuals) {
+          // The method cannot be invoked, because doing so would drop 
+          // qualifiers.
+          return;
+        }
+      }
+  
   // Insert this result into the set of results.
   Results.push_back(R);
 }
@@ -2364,6 +2398,13 @@ void Sema::CodeCompleteOrdinaryName(Scope *S,
     break;
   }
 
+  // If we are in a C++ non-static member function, check the qualifiers on
+  // the member function to filter/prioritize the results list.
+  if (CXXMethodDecl *CurMethod = dyn_cast<CXXMethodDecl>(CurContext))
+    if (CurMethod->isInstance())
+      Results.setObjectTypeQualifiers(
+                      Qualifiers::fromCVRMask(CurMethod->getTypeQualifiers()));
+  
   CodeCompletionDeclConsumer Consumer(Results, CurContext);
   LookupVisibleDecls(S, LookupOrdinaryName, Consumer,
                      CodeCompleter->includeGlobals());
@@ -2566,7 +2607,7 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE,
     if (const PointerType *Ptr = BaseType->getAs<PointerType>())
       BaseType = Ptr->getPointeeType();
     else if (BaseType->isObjCObjectPointerType())
-    /*Do nothing*/ ;
+      /*Do nothing*/ ;
     else
       return;
   }
@@ -2574,6 +2615,10 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE,
   ResultBuilder Results(*this, &ResultBuilder::IsMember);
   Results.EnterNewScope();
   if (const RecordType *Record = BaseType->getAs<RecordType>()) {
+    // Indicate that we are performing a member access, and the cv-qualifiers
+    // for the base object type.
+    Results.setObjectTypeQualifiers(BaseType.getQualifiers());
+    
     // Access to a C/C++ class, struct, or union.
     Results.allowNestedNameSpecifiers();
     CodeCompletionDeclConsumer Consumer(Results, CurContext);
diff --git a/test/Index/complete-memfunc-cvquals.cpp b/test/Index/complete-memfunc-cvquals.cpp
new file mode 100644 (file)
index 0000000..08acdd1
--- /dev/null
@@ -0,0 +1,78 @@
+// The run lines are below, because this test is line- and
+// column-number sensitive.
+struct Foo {
+  void babble() const volatile;
+  void bar();
+  void baz() const;
+  void bingo() volatile;
+  void theend() const volatile;
+};
+
+template<typename T>
+struct smart_ptr {
+  T *operator->();
+  const T* operator->() const;
+};
+
+void text(Foo f, Foo *fp, const Foo &fc, const Foo *fcp,
+          smart_ptr<Foo> sf, const smart_ptr<Foo> &sfc, Foo volatile *fvp) {
+  f.bar();
+  fp->bar();
+  fc.baz();
+  fcp->baz();
+  sf->bar();
+  sfc->baz();
+  fvp->babble();
+}
+
+void Foo::bar() {
+  
+}
+
+void Foo::baz() const {
+
+}
+
+void Foo::bingo() volatile {
+
+}
+
+// Check member access expressions.
+// RUN: c-index-test -code-completion-at=%s:19:5 %s | FileCheck -check-prefix=CHECK-NOQUALS %s
+// RUN: c-index-test -code-completion-at=%s:20:7 %s | FileCheck -check-prefix=CHECK-NOQUALS %s
+// RUN: c-index-test -code-completion-at=%s:23:7 %s | FileCheck -check-prefix=CHECK-NOQUALS %s
+// CHECK-NOQUALS: FunctionDecl:{ResultType void}{TypedText babble}{LeftParen (}{RightParen )}{Informative  const volatile} (20)
+// CHECK-NOQUALS: FunctionDecl:{ResultType void}{TypedText bar}{LeftParen (}{RightParen )} (19)
+// CHECK-NOQUALS: FunctionDecl:{ResultType void}{TypedText baz}{LeftParen (}{RightParen )}{Informative  const} (20)
+// CHECK-NOQUALS: FunctionDecl:{ResultType void}{TypedText bingo}{LeftParen (}{RightParen )}{Informative  volatile} (20)
+// RUN: c-index-test -code-completion-at=%s:21:6 %s | FileCheck -check-prefix=CHECK-CONST %s
+// RUN: c-index-test -code-completion-at=%s:22:8 %s | FileCheck -check-prefix=CHECK-CONST %s
+// RUN: c-index-test -code-completion-at=%s:24:8 %s | FileCheck -check-prefix=CHECK-CONST %s
+// CHECK-CONST: FunctionDecl:{ResultType void}{TypedText babble}{LeftParen (}{RightParen )}{Informative  const volatile} (20)
+// CHECK-CONST-NOT: bar
+// CHECK-CONST: FunctionDecl:{ResultType void}{TypedText baz}{LeftParen (}{RightParen )}{Informative  const} (19)
+// CHECK-CONST-NOT: bingo
+// CHECK-CONST: theend
+// RUN: c-index-test -code-completion-at=%s:25:8 %s | FileCheck -check-prefix=CHECK-VOLATILE %s
+// CHECK-VOLATILE: FunctionDecl:{ResultType void}{TypedText babble}{LeftParen (}{RightParen )}{Informative  const volatile} (20)
+// CHECK-VOLATILE-NOT: baz
+// CHECK-VOLATILE: FunctionDecl:{ResultType void}{TypedText bingo}{LeftParen (}{RightParen )}{Informative  volatile} (19)
+
+// Check implicit member access expressions.
+// RUN: c-index-test -code-completion-at=%s:29:2 %s | FileCheck -check-prefix=CHECK-IMPLICIT-NOQUALS %s
+// CHECK-IMPLICIT-NOQUALS: FunctionDecl:{ResultType void}{TypedText babble}{LeftParen (}{RightParen )}{Informative  const volatile} (15)
+// CHECK-IMPLICIT-NOQUALS: FunctionDecl:{ResultType void}{TypedText bar}{LeftParen (}{RightParen )} (14)
+// CHECK-IMPLICIT-NOQUALS: FunctionDecl:{ResultType void}{TypedText baz}{LeftParen (}{RightParen )}{Informative  const} (15)
+// CHECK-IMPLICIT-NOQUALS: FunctionDecl:{ResultType void}{TypedText bingo}{LeftParen (}{RightParen )}{Informative  volatile} (15)
+
+// RUN: c-index-test -code-completion-at=%s:33:1 %s | FileCheck -check-prefix=CHECK-IMPLICIT-CONST %s
+// CHECK-IMPLICIT-CONST: FunctionDecl:{ResultType void}{TypedText babble}{LeftParen (}{RightParen )}{Informative  const volatile} (15)
+// CHECK-IMPLICIT-CONST-NOT: bar
+// CHECK-IMPLICIT-CONST: FunctionDecl:{ResultType void}{TypedText baz}{LeftParen (}{RightParen )}{Informative  const} (14)
+// CHECK-IMPLICIT-CONST-NOT: bingo
+// CHECK-IMPLICIT-CONST: theend
+
+// RUN: c-index-test -code-completion-at=%s:37:1 %s | FileCheck -check-prefix=CHECK-IMPLICIT-VOLATILE %s
+// CHECK-IMPLICIT-VOLATILE: FunctionDecl:{ResultType void}{TypedText babble}{LeftParen (}{RightParen )}{Informative  const volatile} (15)
+// CHECK-IMPLICIT-VOLATILE-NOT: baz
+// CHECK-IMPLICIT-VOLATILE: FunctionDecl:{ResultType void}{TypedText bingo}{LeftParen (}{RightParen )}{Informative  volatile} (14)