diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/Sema/SemaAccess.cpp | 27 | ||||
-rw-r--r-- | clang/lib/Sema/SemaCodeComplete.cpp | 29 |
2 files changed, 42 insertions, 14 deletions
diff --git a/clang/lib/Sema/SemaAccess.cpp b/clang/lib/Sema/SemaAccess.cpp index 44d41ea4b05..9fbae2ca297 100644 --- a/clang/lib/Sema/SemaAccess.cpp +++ b/clang/lib/Sema/SemaAccess.cpp @@ -11,6 +11,7 @@ // //===----------------------------------------------------------------------===// +#include "clang/Basic/Specifiers.h" #include "clang/Sema/SemaInternal.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" @@ -1856,29 +1857,31 @@ void Sema::CheckLookupAccess(const LookupResult &R) { } } -/// Checks access to Decl from the given class. The check will take access +/// Checks access to Target from the given class. The check will take access /// specifiers into account, but no member access expressions and such. /// -/// \param Decl the declaration to check if it can be accessed +/// \param Target the declaration to check if it can be accessed /// \param Ctx the class/context from which to start the search -/// \return true if the Decl is accessible from the Class, false otherwise. -bool Sema::IsSimplyAccessible(NamedDecl *Decl, DeclContext *Ctx) { +/// \return true if the Target is accessible from the Class, false otherwise. +bool Sema::IsSimplyAccessible(NamedDecl *Target, DeclContext *Ctx) { if (CXXRecordDecl *Class = dyn_cast<CXXRecordDecl>(Ctx)) { - if (!Decl->isCXXClassMember()) + if (!Target->isCXXClassMember()) return true; + if (Target->getAccess() == AS_public) + return true; QualType qType = Class->getTypeForDecl()->getCanonicalTypeInternal(); + // The unprivileged access is AS_none as we don't know how the member was + // accessed, which is described by the access in DeclAccessPair. + // `IsAccessible` will examine the actual access of Target (i.e. + // Decl->getAccess()) when calculating the access. AccessTarget Entity(Context, AccessedEntity::Member, Class, - DeclAccessPair::make(Decl, Decl->getAccess()), - qType); - if (Entity.getAccess() == AS_public) - return true; - + DeclAccessPair::make(Target, AS_none), qType); EffectiveContext EC(CurContext); return ::IsAccessible(*this, EC, Entity) != ::AR_inaccessible; } - - if (ObjCIvarDecl *Ivar = dyn_cast<ObjCIvarDecl>(Decl)) { + + if (ObjCIvarDecl *Ivar = dyn_cast<ObjCIvarDecl>(Target)) { // @public and @package ivars are always accessible. if (Ivar->getCanonicalAccessControl() == ObjCIvarDecl::Public || Ivar->getCanonicalAccessControl() == ObjCIvarDecl::Package) diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp index 700f5a2fee2..ae5183408f1 100644 --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -1303,8 +1303,33 @@ namespace { void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, DeclContext *Ctx, bool InBaseClass) override { bool Accessible = true; - if (Ctx) - Accessible = Results.getSema().IsSimplyAccessible(ND, Ctx); + if (Ctx) { + DeclContext *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", when looking up in `B`. We need to set the actual + // accessing context (i.e. naming class) to "D" so that access can be + // calculated correctly. + if (InBaseClass && isa<CXXRecordDecl>(Ctx)) { + CXXRecordDecl *RC = nullptr; + // Get the enclosing record. + for (DeclContext *DC = CurContext; !DC->isFileContext(); + DC = DC->getParent()) { + if ((RC = 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); |