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