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(Decl)) { // @public and @package ivars are always accessible. if (Ivar->getCanonicalAccessControl() == ObjCIvarDecl::Public || 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(Ctx)) { + CXXRecordDecl *RC = nullptr; + // Get the enclosing record. + for (auto *DC = CurContext; !DC->isFileContext(); + DC = DC->getParent()) { + if ((RC = llvm::dyn_cast(DC))) + break; + } + if (RC) + AccessingCtx = RC; + } + Accessible = Results.getSema().IsSimplyAccessible(ND, AccessingCtx); + } ResultBuilder::Result Result(ND, Results.getBasePriority(ND), nullptr, false, Accessible, FixIts); 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) +}