ioeric created this revision.
ioeric added reviewers: aaron.ballman, sammccall.
Herald added a subscriber: cfe-commits.

Currently, protected members from base classes are marked as
inaccessible when completing in derived class. This patch fixes the problem by
setting the naming class correctly when looking up results in base class
according to [11.2.p5].


Repository:
  rC Clang

https://reviews.llvm.org/D49421

Files:
  lib/Sema/SemaAccess.cpp
  lib/Sema/SemaCodeComplete.cpp
  test/Index/complete-access-checks.cpp

Index: test/Index/complete-access-checks.cpp
===================================================================
--- test/Index/complete-access-checks.cpp
+++ test/Index/complete-access-checks.cpp
@@ -36,10 +36,10 @@
 
 // CHECK-SUPER-ACCESS: CXXMethod:{ResultType void}{TypedText doSomething}{LeftParen (}{RightParen )} (34)
 // CHECK-SUPER-ACCESS: CXXMethod:{ResultType void}{Informative X::}{TypedText func1}{LeftParen (}{RightParen )} (36)
-// CHECK-SUPER-ACCESS: CXXMethod:{ResultType void}{Informative X::}{TypedText func2}{LeftParen (}{RightParen )} (36) (inaccessible)
+// CHECK-SUPER-ACCESS: CXXMethod:{ResultType void}{Informative X::}{TypedText func2}{LeftParen (}{RightParen )} (36)
 // CHECK-SUPER-ACCESS: CXXMethod:{ResultType void}{Informative X::}{TypedText func3}{LeftParen (}{RightParen )} (36) (inaccessible)
 // CHECK-SUPER-ACCESS: FieldDecl:{ResultType int}{Informative X::}{TypedText member1} (37)
-// CHECK-SUPER-ACCESS: FieldDecl:{ResultType int}{Informative X::}{TypedText member2} (37) (inaccessible)
+// CHECK-SUPER-ACCESS: FieldDecl:{ResultType int}{Informative X::}{TypedText member2} (37)
 // CHECK-SUPER-ACCESS: FieldDecl:{ResultType int}{Informative X::}{TypedText member3} (37) (inaccessible)
 // CHECK-SUPER-ACCESS: CXXMethod:{ResultType Y &}{TypedText operator=}{LeftParen (}{Placeholder const Y &}{RightParen )} (79)
 // CHECK-SUPER-ACCESS: CXXMethod:{ResultType X &}{Text X::}{TypedText operator=}{LeftParen (}{Placeholder const X &}{RightParen )} (81)
@@ -87,3 +87,26 @@
 // CHECK-USING-ACCESSIBLE: ClassDecl:{TypedText Q}{Text ::} (75)
 // CHECK-USING-ACCESSIBLE: CXXDestructor:{ResultType void}{Informative P::}{TypedText ~P}{LeftParen (}{RightParen )} (81)
 // CHECK-USING-ACCESSIBLE: CXXDestructor:{ResultType void}{TypedText ~Q}{LeftParen (}{RightParen )} (79)
+
+class B {
+protected:
+  int member;
+};
+
+class C : private B {};
+
+
+class D : public C {
+ public:
+  void f(::B *b);
+};
+
+void D::f(::B *that) {
+  // RUN: c-index-test -code-completion-at=%s:106:9 %s | FileCheck -check-prefix=CHECK-PRIVATE-SUPER-THIS %s
+  this->;
+// CHECK-PRIVATE-SUPER-THIS: FieldDecl:{ResultType int}{Informative B::}{TypedText member} (37) (inaccessible)
+
+  // RUN: c-index-test -code-completion-at=%s:110:9 %s | FileCheck -check-prefix=CHECK-PRIVATE-SUPER-THAT %s
+  that->;
+// CHECK-PRIVATE-SUPER-THAT: FieldDecl:{ResultType int}{TypedText member} (35) (inaccessible)
+}
Index: lib/Sema/SemaCodeComplete.cpp
===================================================================
--- lib/Sema/SemaCodeComplete.cpp
+++ lib/Sema/SemaCodeComplete.cpp
@@ -1303,8 +1303,32 @@
     void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, DeclContext *Ctx,
                    bool InBaseClass) override {
       bool Accessible = true;
-      if (Ctx)
-        Accessible = Results.getSema().IsSimplyAccessible(ND, Ctx);
+      if (Ctx) {
+        auto *AccessingCtx = Ctx;
+        // If ND comes from a base class, set the naming class back to the
+        // derived class if the search starts from the derived class (i.e.
+        // InBaseClass is true).
+        //
+        // Example:
+        //   class B { protected: int X; }
+        //   class D : public B { void f(); }
+        //   void D::f() { this->^; }
+        // The completion after "this->" will have `InBaseClass` set to true and
+        // `Ctx` set to "B". We need to set the actual accessing context (i.e.
+        // naming class) to "D" so that access can be calculated correctly.
+        if (InBaseClass && llvm::isa<CXXRecordDecl>(Ctx)) {
+          CXXRecordDecl *RC = nullptr;
+          // Get the enclosing record.
+          for (auto *DC = CurContext; !DC->isFileContext();
+               DC = DC->getParent()) {
+            if ((RC = llvm::dyn_cast<CXXRecordDecl>(DC)))
+              break;
+          }
+          if (RC)
+            AccessingCtx = RC;
+        }
+        Accessible = Results.getSema().IsSimplyAccessible(ND, AccessingCtx);
+      }
 
       ResultBuilder::Result Result(ND, Results.getBasePriority(ND), nullptr,
                                    false, Accessible, FixIts);
Index: lib/Sema/SemaAccess.cpp
===================================================================
--- lib/Sema/SemaAccess.cpp
+++ lib/Sema/SemaAccess.cpp
@@ -1868,16 +1868,15 @@
       return true;
 
     QualType qType = Class->getTypeForDecl()->getCanonicalTypeInternal();
+    // The access should be AS_none as we don't know how the member was
+    // accessed - `AccessedEntity::getAccess` describes what access was used to
+    // access an entity.
     AccessTarget Entity(Context, AccessedEntity::Member, Class,
-                        DeclAccessPair::make(Decl, Decl->getAccess()),
-                        qType);
-    if (Entity.getAccess() == AS_public)
-      return true;
-
+                        DeclAccessPair::make(Decl, AS_none), qType);
     EffectiveContext EC(CurContext);
     return ::IsAccessible(*this, EC, Entity) != ::AR_inaccessible;
   }
-  
+
   if (ObjCIvarDecl *Ivar = dyn_cast<ObjCIvarDecl>(Decl)) {
     // @public and @package ivars are always accessible.
     if (Ivar->getCanonicalAccessControl() == ObjCIvarDecl::Public ||
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to