//
//===----------------------------------------------------------------------===//
#include "clang/AST/Decl.h"
+#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/ExprCXX.h"
void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, DeclContext *Ctx,
bool InBaseClass) override {
- // Naming class to use for access check. In most cases it was provided
- // explicitly (e.g. member access (lhs.foo) or qualified lookup (X::)), for
- // unqualified lookup we fallback to the \p Ctx in which we found the
- // member.
- auto *NamingClass = this->NamingClass;
- if (!NamingClass)
- NamingClass = llvm::dyn_cast_or_null<CXXRecordDecl>(Ctx);
- bool Accessible =
- Results.getSema().IsSimplyAccessible(ND, NamingClass, BaseType);
ResultBuilder::Result Result(ND, Results.getBasePriority(ND), nullptr,
- false, Accessible, FixIts);
+ false, IsAccessible(ND, Ctx), FixIts);
Results.AddResult(Result, InitialLookupCtx, Hiding, InBaseClass);
}
void EnteredContext(DeclContext *Ctx) override {
Results.addVisitedContext(Ctx);
}
+
+private:
+ bool IsAccessible(NamedDecl *ND, DeclContext *Ctx) {
+ // Naming class to use for access check. In most cases it was provided
+ // explicitly (e.g. member access (lhs.foo) or qualified lookup (X::)),
+ // for unqualified lookup we fallback to the \p Ctx in which we found the
+ // member.
+ auto *NamingClass = this->NamingClass;
+ QualType BaseType = this->BaseType;
+ if (auto *Cls = llvm::dyn_cast_or_null<CXXRecordDecl>(Ctx)) {
+ if (!NamingClass)
+ NamingClass = Cls;
+ // When we emulate implicit 'this->' in an unqualified lookup, we might
+ // end up with an invalid naming class. In that case, we avoid emulating
+ // 'this->' qualifier to satisfy preconditions of the access checking.
+ if (NamingClass->getCanonicalDecl() != Cls->getCanonicalDecl() &&
+ !NamingClass->isDerivedFrom(Cls)) {
+ NamingClass = Cls;
+ BaseType = QualType();
+ }
+ } else {
+ // The decl was found outside the C++ class, so only ObjC access checks
+ // apply. Those do not rely on NamingClass and BaseType, so we clear them
+ // out.
+ NamingClass = nullptr;
+ BaseType = QualType();
+ }
+ return Results.getSema().IsSimplyAccessible(ND, NamingClass, BaseType);
+ }
};
} // namespace
// RUN: | FileCheck -check-prefix=UNRELATED %s
}
};
+
+class Outer {
+ public:
+ static int pub;
+ protected:
+ static int prot;
+ private:
+ static int priv;
+
+ class Inner {
+ int test() {
+ Outer::pub = 10;
+ // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:85:14 %s -o - \
+ // RUN: | FileCheck -check-prefix=OUTER %s
+ // OUTER: priv : [#int#]priv
+ // OUTER: prot : [#int#]prot
+ // OUTER: pub : [#int#]pub
+
+ // Also check the unqualified case.
+ // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:85:1 %s -o - \
+ // RUN: | FileCheck -check-prefix=OUTER %s
+ }
+ };
+};
+
+class Base {
+public:
+ int pub;
+};
+
+class Accessible : public Base {
+};
+
+class Inaccessible : private Base {
+};
+
+class Test : public Accessible, public Inaccessible {
+ int test() {
+ this->Accessible::pub = 10;
+ // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:112:23 %s -o - \
+ // RUN: | FileCheck -check-prefix=ACCESSIBLE %s
+ // ACCESSIBLE: pub (InBase)
+
+ this->Inaccessible::pub = 10;
+ // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:117:25 %s -o - \
+ // RUN: | FileCheck -check-prefix=INACCESSIBLE %s
+ // INACCESSIBLE: pub (InBase,Inaccessible)
+ }
+};