From: Erik Verbruggen Date: Thu, 6 Oct 2011 07:27:49 +0000 (+0000) Subject: Added CXAvailability_NotAccessible to indicate that a declaration is available, but... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d12059673dcef32bc2b6bae5321654d33863afe6;p=clang Added CXAvailability_NotAccessible to indicate that a declaration is available, but not accessible from the current code completion context. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@141278 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h index 05ac19bb23..ea4261fe20 100644 --- a/include/clang-c/Index.h +++ b/include/clang-c/Index.h @@ -115,7 +115,12 @@ enum CXAvailabilityKind { /** * \brief The entity is not available; any use of it will be an error. */ - CXAvailability_NotAvailable + CXAvailability_NotAvailable, + /** + * \brief The entity is available, but not accessible; any use of it will be + * an error. + */ + CXAvailability_NotAccessible }; /** diff --git a/include/clang/Sema/CodeCompleteConsumer.h b/include/clang/Sema/CodeCompleteConsumer.h index 2213c7c7e6..a20468e20b 100644 --- a/include/clang/Sema/CodeCompleteConsumer.h +++ b/include/clang/Sema/CodeCompleteConsumer.h @@ -632,14 +632,15 @@ public: /// \brief Build a result that refers to a declaration. CodeCompletionResult(NamedDecl *Declaration, NestedNameSpecifier *Qualifier = 0, - bool QualifierIsInformative = false) + bool QualifierIsInformative = false, + bool Accessible = true) : Kind(RK_Declaration), Declaration(Declaration), Priority(getPriorityFromDecl(Declaration)), Availability(CXAvailability_Available), StartParameter(0), Hidden(false), QualifierIsInformative(QualifierIsInformative), StartsNestedNameSpecifier(false), AllParametersAreInformative(false), DeclaringEntity(false), Qualifier(Qualifier) { - computeCursorKindAndAvailability(); + computeCursorKindAndAvailability(Accessible); } /// \brief Build a result that refers to a keyword or symbol. @@ -701,7 +702,7 @@ public: static unsigned getPriorityFromDecl(NamedDecl *ND); private: - void computeCursorKindAndAvailability(); + void computeCursorKindAndAvailability(bool Accessible = true); }; bool operator<(const CodeCompletionResult &X, const CodeCompletionResult &Y); diff --git a/include/clang/Sema/Lookup.h b/include/clang/Sema/Lookup.h index 71b996a156..6630bb2981 100644 --- a/include/clang/Sema/Lookup.h +++ b/include/clang/Sema/Lookup.h @@ -636,9 +636,11 @@ private: /// \param Hiding a declaration that hides the declaration \p ND, /// or NULL if no such declaration exists. /// + /// \param Ctx the original context from which the lookup started. + /// /// \param InBaseClass whether this declaration was found in base /// class of the context we searched. - virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, + virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, DeclContext *Ctx, bool InBaseClass) = 0; }; diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index bf8f9c81e4..aad52fcab8 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -3693,6 +3693,7 @@ public: bool ForceCheck = false, bool ForceUnprivileged = false); void CheckLookupAccess(const LookupResult &R); + bool IsSimplyAccessible(NamedDecl *decl, CXXRecordDecl *Class); void HandleDependentAccessCheck(const DependentDiagnostic &DD, const MultiLevelTemplateArgumentList &TemplateArgs); diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp index 3db9e4dcd5..ab699382e6 100644 --- a/lib/Sema/CodeCompleteConsumer.cpp +++ b/lib/Sema/CodeCompleteConsumer.cpp @@ -376,7 +376,7 @@ PrintingCodeCompleteConsumer::ProcessOverloadCandidates(Sema &SemaRef, } } -void CodeCompletionResult::computeCursorKindAndAvailability() { +void CodeCompletionResult::computeCursorKindAndAvailability(bool Accessible) { switch (Kind) { case RK_Declaration: // Set the availability based on attributes. @@ -418,6 +418,9 @@ void CodeCompletionResult::computeCursorKindAndAvailability() { // Do nothing: Patterns can come with cursor kinds! break; } + + if (!Accessible) + Availability = CXAvailability_NotAccessible; } /// \brief Retrieve the name that should be used to order a result. diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp index a2d078b12c..14c8ebafe7 100644 --- a/lib/Sema/SemaAccess.cpp +++ b/lib/Sema/SemaAccess.cpp @@ -1641,6 +1641,27 @@ void Sema::CheckLookupAccess(const LookupResult &R) { } } +/// Checks access to Decl 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 Class 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, CXXRecordDecl *Class) { + if (!Class) + return true; + + QualType qType = Class->getTypeForDecl()->getCanonicalTypeInternal(); + AccessTarget Entity(Context, AccessedEntity::Member, Class, + DeclAccessPair::make(Decl, Decl->getAccess()), + qType); + if (Entity.getAccess() == AS_public) + return true; + + EffectiveContext EC(CurContext); + return ::IsAccessible(*this, EC, Entity) != ::AR_inaccessible; +} + void Sema::ActOnStartSuppressingAccessChecks() { assert(!SuppressAccessChecking && "Tried to start access check suppression when already started."); diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index 5b7f251c4c..56b351c4cf 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -1186,8 +1186,16 @@ namespace { CodeCompletionDeclConsumer(ResultBuilder &Results, DeclContext *CurContext) : Results(Results), CurContext(CurContext) { } - virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, bool InBaseClass) { - Results.AddResult(ND, CurContext, Hiding, InBaseClass); + virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, DeclContext *Ctx, + bool InBaseClass) { + bool Accessible = true; + if (Ctx) { + if (CXXRecordDecl *Class = dyn_cast(Ctx)) + Accessible = Results.getSema().IsSimplyAccessible(ND, Class); + // FIXME: ObjC access checks are missing. + } + ResultBuilder::Result Result(ND, 0, false, Accessible); + Results.AddResult(Result, CurContext, Hiding, InBaseClass); } }; } diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index f11737b9f7..84ae42a9b9 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -2701,7 +2701,7 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, D != DEnd; ++D) { if (NamedDecl *ND = dyn_cast(*D)) { if (Result.isAcceptableDecl(ND)) { - Consumer.FoundDecl(ND, Visited.checkHidden(ND), InBaseClass); + Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass); Visited.add(ND); } } else if (ObjCForwardProtocolDecl *ForwardProto @@ -2712,14 +2712,15 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, P != PEnd; ++P) { if (Result.isAcceptableDecl(*P)) { - Consumer.FoundDecl(*P, Visited.checkHidden(*P), InBaseClass); + Consumer.FoundDecl(*P, Visited.checkHidden(*P), Ctx, InBaseClass); Visited.add(*P); } } } else if (ObjCClassDecl *Class = dyn_cast(*D)) { ObjCInterfaceDecl *IFace = Class->getForwardInterfaceDecl(); if (Result.isAcceptableDecl(IFace)) { - Consumer.FoundDecl(IFace, Visited.checkHidden(IFace), InBaseClass); + Consumer.FoundDecl(IFace, Visited.checkHidden(IFace), Ctx, + InBaseClass); Visited.add(IFace); } } @@ -2861,7 +2862,7 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result, D != DEnd; ++D) { if (NamedDecl *ND = dyn_cast(*D)) if (Result.isAcceptableDecl(ND)) { - Consumer.FoundDecl(ND, Visited.checkHidden(ND), false); + Consumer.FoundDecl(ND, Visited.checkHidden(ND), 0, false); Visited.add(ND); } } @@ -3043,7 +3044,8 @@ public: delete I->second; } - virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, bool InBaseClass); + virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, DeclContext *Ctx, + bool InBaseClass); void FoundName(StringRef Name); void addKeywordResult(StringRef Keyword); void addName(StringRef Name, NamedDecl *ND, unsigned Distance, @@ -3074,7 +3076,7 @@ public: } void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding, - bool InBaseClass) { + DeclContext *Ctx, bool InBaseClass) { // Don't consider hidden names for typo correction. if (Hiding) return; diff --git a/test/Index/complete-access-checks.cpp b/test/Index/complete-access-checks.cpp new file mode 100644 index 0000000000..c77a5d656a --- /dev/null +++ b/test/Index/complete-access-checks.cpp @@ -0,0 +1,89 @@ +struct X { + int member1; + void func1(); +protected: + int member2; + void func2(); +private: + int member3; + void func3(); +}; + +struct Y: protected X { + void doSomething(); +}; + +class Z { +public: + int member1; + void func1(); +protected: + int member2; + void func2(); +private: + int member3; + void func3(); +}; + +void Y::doSomething() { + // RUN: c-index-test -code-completion-at=%s:30:9 %s | FileCheck -check-prefix=CHECK-SUPER-ACCESS %s + this->; + + Z that; + // RUN: c-index-test -code-completion-at=%s:34:8 %s | FileCheck -check-prefix=CHECK-ACCESS %s + that. +} + +// 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 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 member3} (37) (inaccessible) +// CHECK-SUPER-ACCESS: CXXMethod:{ResultType Y &}{TypedText operator=}{LeftParen (}{Placeholder const Y &}{RightParen )} (34) +// CHECK-SUPER-ACCESS: CXXMethod:{ResultType X &}{Text X::}{TypedText operator=}{LeftParen (}{Placeholder const X &}{RightParen )} (36) +// CHECK-SUPER-ACCESS: StructDecl:{TypedText X}{Text ::} (77) +// CHECK-SUPER-ACCESS: StructDecl:{TypedText Y}{Text ::} (75) +// CHECK-SUPER-ACCESS: CXXDestructor:{ResultType void}{Informative X::}{TypedText ~X}{LeftParen (}{RightParen )} (36) +// CHECK-SUPER-ACCESS: CXXDestructor:{ResultType void}{TypedText ~Y}{LeftParen (}{RightParen )} (34) + +// CHECK-ACCESS: CXXMethod:{ResultType void}{TypedText func1}{LeftParen (}{RightParen )} (34) +// CHECK-ACCESS: CXXMethod:{ResultType void}{TypedText func2}{LeftParen (}{RightParen )} (34) (inaccessible) +// CHECK-ACCESS: CXXMethod:{ResultType void}{TypedText func3}{LeftParen (}{RightParen )} (34) (inaccessible) +// CHECK-ACCESS: FieldDecl:{ResultType int}{TypedText member1} (35) +// CHECK-ACCESS: FieldDecl:{ResultType int}{TypedText member2} (35) (inaccessible) +// CHECK-ACCESS: FieldDecl:{ResultType int}{TypedText member3} (35) (inaccessible) +// CHECK-ACCESS: CXXMethod:{ResultType Z &}{TypedText operator=}{LeftParen (}{Placeholder const Z &}{RightParen )} (34) +// CHECK-ACCESS: ClassDecl:{TypedText Z}{Text ::} (75) +// CHECK-ACCESS: CXXDestructor:{ResultType void}{TypedText ~Z}{LeftParen (}{RightParen )} (34) + +class P { +protected: + int member; +}; + +class Q : public P { +public: + using P::member; +}; + +void f(P x, Q y) { + // RUN: c-index-test -code-completion-at=%s:73:5 %s | FileCheck -check-prefix=CHECK-USING-INACCESSIBLE %s + x.; // member is inaccessible + // RUN: c-index-test -code-completion-at=%s:75:5 %s | FileCheck -check-prefix=CHECK-USING-ACCESSIBLE %s + y.; // member is accessible +} + +// CHECK-USING-INACCESSIBLE: FieldDecl:{ResultType int}{TypedText member} (35) (inaccessible) +// CHECK-USING-INACCESSIBLE: CXXMethod:{ResultType P &}{TypedText operator=}{LeftParen (}{Placeholder const P &}{RightParen )} (34) +// CHECK-USING-INACCESSIBLE: ClassDecl:{TypedText P}{Text ::} (75) +// CHECK-USING-INACCESSIBLE: CXXDestructor:{ResultType void}{TypedText ~P}{LeftParen (}{RightParen )} (34) + +// CHECK-USING-ACCESSIBLE: FieldDecl:{ResultType int}{TypedText member} (35) +// CHECK-USING-ACCESSIBLE: CXXMethod:{ResultType Q &}{TypedText operator=}{LeftParen (}{Placeholder const Q &}{RightParen )} (34) +// CHECK-USING-ACCESSIBLE: CXXMethod:{ResultType P &}{Text P::}{TypedText operator=}{LeftParen (}{Placeholder const P &}{RightParen )} (36) +// CHECK-USING-ACCESSIBLE: ClassDecl:{TypedText P}{Text ::} (77) +// CHECK-USING-ACCESSIBLE: ClassDecl:{TypedText Q}{Text ::} (75) +// CHECK-USING-ACCESSIBLE: CXXDestructor:{ResultType void}{Informative P::}{TypedText ~P}{LeftParen (}{RightParen )} (36) +// CHECK-USING-ACCESSIBLE: CXXDestructor:{ResultType void}{TypedText ~Q}{LeftParen (}{RightParen )} (34) diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c index 69a179f177..1f78a6ffaa 100644 --- a/tools/c-index-test/c-index-test.c +++ b/tools/c-index-test/c-index-test.c @@ -238,6 +238,10 @@ static void PrintCursor(CXCursor Cursor) { case CXAvailability_NotAvailable: printf(" (unavailable)"); break; + + case CXAvailability_NotAccessible: + printf(" (inaccessible)"); + break; } if (clang_CXXMethod_isStatic(Cursor)) @@ -1051,6 +1055,10 @@ void print_completion_result(CXCompletionResult *completion_result, case CXAvailability_NotAvailable: fprintf(file, " (unavailable)"); break; + + case CXAvailability_NotAccessible: + fprintf(file, " (inaccessible)"); + break; } fprintf(file, "\n"); }