aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Sema
diff options
context:
space:
mode:
authorIlya Biryukov <ibiryukov@google.com>2018-12-03 13:29:17 +0000
committerIlya Biryukov <ibiryukov@google.com>2018-12-03 13:29:17 +0000
commitf1822ec431cded5e50b69152346794d79976a8b2 (patch)
tree367d6815eb69d834b7d7236ed170ddc9b5cb6d56 /clang/lib/Sema
parent6ef089d21c8853d4623980617f18490ab64c8548 (diff)
downloadllvm-f1822ec431cded5e50b69152346794d79976a8b2.zip
llvm-f1822ec431cded5e50b69152346794d79976a8b2.tar.gz
llvm-f1822ec431cded5e50b69152346794d79976a8b2.tar.bz2
[CodeComplete] Cleanup access checking in code completion
Summary: Also fixes a crash (see the added 'accessibility-crash.cpp' test). Reviewers: ioeric, kadircet Reviewed By: kadircet Subscribers: cfe-commits Differential Revision: https://reviews.llvm.org/D55124 llvm-svn: 348135
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r--clang/lib/Sema/CodeCompleteConsumer.cpp3
-rw-r--r--clang/lib/Sema/SemaAccess.cpp29
-rw-r--r--clang/lib/Sema/SemaCodeComplete.cpp71
3 files changed, 63 insertions, 40 deletions
diff --git a/clang/lib/Sema/CodeCompleteConsumer.cpp b/clang/lib/Sema/CodeCompleteConsumer.cpp
index f6a959c..40db849 100644
--- a/clang/lib/Sema/CodeCompleteConsumer.cpp
+++ b/clang/lib/Sema/CodeCompleteConsumer.cpp
@@ -555,6 +555,9 @@ void PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(
Tags.push_back("Hidden");
if (Results[I].InBaseClass)
Tags.push_back("InBase");
+ if (Results[I].Availability ==
+ CXAvailabilityKind::CXAvailability_NotAccessible)
+ Tags.push_back("Inaccessible");
if (!Tags.empty())
OS << " (" << llvm::join(Tags, ",") << ")";
}
diff --git a/clang/lib/Sema/SemaAccess.cpp b/clang/lib/Sema/SemaAccess.cpp
index cf33231..0432e70 100644
--- a/clang/lib/Sema/SemaAccess.cpp
+++ b/clang/lib/Sema/SemaAccess.cpp
@@ -1877,22 +1877,33 @@ void Sema::CheckLookupAccess(const LookupResult &R) {
/// specifiers into account, but no member access expressions and such.
///
/// \param Target the declaration to check if it can be accessed
-/// \param Ctx the class/context from which to start the search
+/// \param NamingClass the class in which the lookup was started.
+/// \param BaseType type of the left side of member access expression.
+/// \p BaseType and \p NamingClass are used for C++ access control.
+/// Depending on the lookup case, they should be set to the following:
+/// - lhs.target (member access without a qualifier):
+/// \p BaseType and \p NamingClass are both the type of 'lhs'.
+/// - lhs.X::target (member access with a qualifier):
+/// BaseType is the type of 'lhs', NamingClass is 'X'
+/// - X::target (qualified lookup without member access):
+/// BaseType is null, NamingClass is 'X'.
+/// - target (unqualified lookup).
+/// BaseType is null, NamingClass is the parent class of 'target'.
/// \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 (!Target->isCXXClassMember())
- return true;
-
+bool Sema::IsSimplyAccessible(NamedDecl *Target, CXXRecordDecl *NamingClass,
+ QualType BaseType) {
+ // Perform the C++ accessibility checks first.
+ if (Target->isCXXClassMember() && NamingClass) {
+ if (!getLangOpts().CPlusPlus)
+ return false;
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(Target, AS_none), qType);
+ AccessTarget Entity(Context, AccessedEntity::Member, NamingClass,
+ DeclAccessPair::make(Target, AS_none), BaseType);
EffectiveContext EC(CurContext);
return ::IsAccessible(*this, EC, Entity) != ::AR_inaccessible;
}
diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp
index aeb7aee..cb66a01 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -1278,38 +1278,53 @@ bool ResultBuilder::IsObjCIvar(const NamedDecl *ND) const {
}
namespace {
+
/// Visible declaration consumer that adds a code-completion result
/// for each visible declaration.
class CodeCompletionDeclConsumer : public VisibleDeclConsumer {
ResultBuilder &Results;
- DeclContext *CurContext;
+ DeclContext *InitialLookupCtx;
+ // NamingClass and BaseType are used for access-checking. See
+ // Sema::IsSimplyAccessible for details.
+ CXXRecordDecl *NamingClass;
+ QualType BaseType;
std::vector<FixItHint> FixIts;
- // This is set to the record where the search starts, if this is a record
- // member completion.
- RecordDecl *MemberCompletionRecord = nullptr;
public:
CodeCompletionDeclConsumer(
- ResultBuilder &Results, DeclContext *CurContext,
- std::vector<FixItHint> FixIts = std::vector<FixItHint>(),
- RecordDecl *MemberCompletionRecord = nullptr)
- : Results(Results), CurContext(CurContext), FixIts(std::move(FixIts)),
- MemberCompletionRecord(MemberCompletionRecord) {}
+ ResultBuilder &Results, DeclContext *InitialLookupCtx,
+ QualType BaseType = QualType(),
+ std::vector<FixItHint> FixIts = std::vector<FixItHint>())
+ : Results(Results), InitialLookupCtx(InitialLookupCtx),
+ FixIts(std::move(FixIts)) {
+ NamingClass = llvm::dyn_cast<CXXRecordDecl>(InitialLookupCtx);
+ // If BaseType was not provided explicitly, emulate implicit 'this->'.
+ if (BaseType.isNull()) {
+ auto ThisType = Results.getSema().getCurrentThisType();
+ if (!ThisType.isNull()) {
+ assert(ThisType->isPointerType());
+ BaseType = ThisType->getPointeeType();
+ if (!NamingClass)
+ NamingClass = BaseType->getAsCXXRecordDecl();
+ }
+ }
+ this->BaseType = BaseType;
+ }
void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, DeclContext *Ctx,
bool InBaseClass) override {
- bool Accessible = true;
- if (Ctx) {
- // Set the actual accessing context (i.e. naming class) to the record
- // context where the search starts. When `InBaseClass` is true, `Ctx`
- // will be the base class, which is not the actual naming class.
- DeclContext *AccessingCtx =
- MemberCompletionRecord ? MemberCompletionRecord : Ctx;
- Accessible = Results.getSema().IsSimplyAccessible(ND, AccessingCtx);
- }
+ // 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);
- Results.AddResult(Result, CurContext, Hiding, InBaseClass);
+ Results.AddResult(Result, InitialLookupCtx, Hiding, InBaseClass);
}
void EnteredContext(DeclContext *Ctx) override {
@@ -3699,20 +3714,15 @@ void Sema::CodeCompleteOrdinaryName(Scope *S,
}
// If we are in a C++ non-static member function, check the qualifiers on
- // the member function to filter/prioritize the results list and set the
- // context to the record context so that accessibility check in base class
- // works correctly.
- RecordDecl *MemberCompletionRecord = nullptr;
+ // the member function to filter/prioritize the results list.
if (CXXMethodDecl *CurMethod = dyn_cast<CXXMethodDecl>(CurContext)) {
if (CurMethod->isInstance()) {
Results.setObjectTypeQualifiers(
Qualifiers::fromCVRMask(CurMethod->getTypeQualifiers()));
- MemberCompletionRecord = CurMethod->getParent();
}
}
- CodeCompletionDeclConsumer Consumer(Results, CurContext, /*FixIts=*/{},
- MemberCompletionRecord);
+ CodeCompletionDeclConsumer Consumer(Results, CurContext);
LookupVisibleDecls(S, LookupOrdinaryName, Consumer,
CodeCompleter->includeGlobals(),
CodeCompleter->loadExternal());
@@ -4152,8 +4162,7 @@ AddRecordMembersCompletionResults(Sema &SemaRef, ResultBuilder &Results,
std::vector<FixItHint> FixIts;
if (AccessOpFixIt)
FixIts.emplace_back(AccessOpFixIt.getValue());
- CodeCompletionDeclConsumer Consumer(Results, SemaRef.CurContext,
- std::move(FixIts), RD);
+ CodeCompletionDeclConsumer Consumer(Results, RD, BaseType, std::move(FixIts));
SemaRef.LookupVisibleDecls(RD, Sema::LookupMemberName, Consumer,
SemaRef.CodeCompleter->includeGlobals(),
/*IncludeDependentBases=*/true,
@@ -4283,7 +4292,7 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base,
// Add all ivars from this class and its superclasses.
if (Class) {
- CodeCompletionDeclConsumer Consumer(Results, CurContext);
+ CodeCompletionDeclConsumer Consumer(Results, Class, BaseType);
Results.setFilter(&ResultBuilder::IsObjCIvar);
LookupVisibleDecls(
Class, LookupMemberName, Consumer, CodeCompleter->includeGlobals(),
@@ -4856,7 +4865,7 @@ void Sema::CodeCompleteAssignmentRHS(Scope *S, Expr *LHS) {
}
void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS,
- bool EnteringContext) {
+ bool EnteringContext, QualType BaseType) {
if (SS.isEmpty() || !CodeCompleter)
return;
@@ -4903,7 +4912,7 @@ void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS,
if (CodeCompleter->includeNamespaceLevelDecls() ||
(!Ctx->isNamespace() && !Ctx->isTranslationUnit())) {
- CodeCompletionDeclConsumer Consumer(Results, CurContext);
+ CodeCompletionDeclConsumer Consumer(Results, Ctx, BaseType);
LookupVisibleDecls(Ctx, LookupOrdinaryName, Consumer,
/*IncludeGlobalScope=*/true,
/*IncludeDependentBases=*/true,