]> granicus.if.org Git - clang/commitdiff
Added CXAvailability_NotAccessible to indicate that a declaration is available, but...
authorErik Verbruggen <erikjv@me.com>
Thu, 6 Oct 2011 07:27:49 +0000 (07:27 +0000)
committerErik Verbruggen <erikjv@me.com>
Thu, 6 Oct 2011 07:27:49 +0000 (07:27 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@141278 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang-c/Index.h
include/clang/Sema/CodeCompleteConsumer.h
include/clang/Sema/Lookup.h
include/clang/Sema/Sema.h
lib/Sema/CodeCompleteConsumer.cpp
lib/Sema/SemaAccess.cpp
lib/Sema/SemaCodeComplete.cpp
lib/Sema/SemaLookup.cpp
test/Index/complete-access-checks.cpp [new file with mode: 0644]
tools/c-index-test/c-index-test.c

index 05ac19bb23db577f06057e3e1ab41295a315cd5c..ea4261fe201f66b8b839f7c7aa99d1f0e9481a7c 100644 (file)
@@ -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
 };
   
 /**
index 2213c7c7e6163791b52e599e360fb62db1692f7b..a20468e20b9590658b6a392776737016c6ee4086 100644 (file)
@@ -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);
index 71b996a1565df88cdbded5a856c28050b6cb8285..6630bb2981e281e23bfdb5c80eb1acfd266e2ef2 100644 (file)
@@ -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;
   };
 
index bf8f9c81e48532602d9ca7fdfb73dee3bd010eda..aad52fcab811ea052205eb1405cc69c790eebfb6 100644 (file)
@@ -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);
index 3db9e4dcd523f1059187494e27a3262b4dec0d85..ab699382e6b42b2fb1c9c09c3d27e52268b68312 100644 (file)
@@ -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.
index a2d078b12c19374f6a02f4c4a3f1ceee0875c0e0..14c8ebafe7d24c668021f6e7623bc26e92234e1c 100644 (file)
@@ -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.");
index 5b7f251c4c9091ae26dd3448e2801716a0b8890d..56b351c4cfb8b3296a4fa6224966d3a8f644d2a1 100644 (file)
@@ -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<CXXRecordDecl>(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);
     }
   };
 }
index f11737b9f7aad335133db954ef8227a351a85c70..84ae42a9b95e464bb960c2f8f459fb05865f0c6c 100644 (file)
@@ -2701,7 +2701,7 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
          D != DEnd; ++D) {
       if (NamedDecl *ND = dyn_cast<NamedDecl>(*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<ObjCClassDecl>(*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<NamedDecl>(*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 (file)
index 0000000..c77a5d6
--- /dev/null
@@ -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)
index 69a179f177c53545f0901b92eb9cbb96c4061571..1f78a6ffaa0eb263926befb13a024ba5e17f63fd 100644 (file)
@@ -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");
 }