zcov: / lib/Sema/SemaAccess.cpp


Files: 1 Branches Taken: 88.0% 95 / 108
Generated: 2010-02-10 01:31 Branches Executed: 100.0% 108 / 108
Line Coverage: 96.1% 146 / 152


Programs: 2 Runs 3018


       1                 : //===---- SemaAccess.cpp - C++ Access Control -------------------*- C++ -*-===//
       2                 : //
       3                 : //                     The LLVM Compiler Infrastructure
       4                 : //
       5                 : // This file is distributed under the University of Illinois Open Source
       6                 : // License. See LICENSE.TXT for details.
       7                 : //
       8                 : //===----------------------------------------------------------------------===//
       9                 : //
      10                 : // This file provides Sema routines for C++ access control semantics.
      11                 : //
      12                 : //===----------------------------------------------------------------------===//
      13                 : 
      14                 : #include "Sema.h"
      15                 : #include "Lookup.h"
      16                 : #include "clang/AST/ASTContext.h"
      17                 : #include "clang/AST/CXXInheritance.h"
      18                 : #include "clang/AST/DeclCXX.h"
      19                 : #include "clang/AST/ExprCXX.h"
      20                 : 
      21                 : using namespace clang;
      22                 : 
      23                 : /// SetMemberAccessSpecifier - Set the access specifier of a member.
      24                 : /// Returns true on error (when the previous member decl access specifier
      25                 : /// is different from the new member decl access specifier).
      26                 : bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl,
      27                 :                                     NamedDecl *PrevMemberDecl,
      28             5737:                                     AccessSpecifier LexicalAS) {
                     5574: branch 0 taken
                      163: branch 1 taken
      29             5737:   if (!PrevMemberDecl) {
      30                 :     // Use the lexical access specifier.
      31             5574:     MemberDecl->setAccess(LexicalAS);
      32             5574:     return false;
      33                 :   }
      34                 : 
      35                 :   // C++ [class.access.spec]p3: When a member is redeclared its access
      36                 :   // specifier must be same as its initial declaration.
                        8: branch 0 taken
                      155: branch 1 taken
                        4: branch 3 taken
                        4: branch 4 taken
                        4: branch 5 taken
                      159: branch 6 taken
      37              163:   if (LexicalAS != AS_none && LexicalAS != PrevMemberDecl->getAccess()) {
      38                 :     Diag(MemberDecl->getLocation(),
      39                 :          diag::err_class_redeclared_with_different_access)
      40                4:       << MemberDecl << LexicalAS;
      41                 :     Diag(PrevMemberDecl->getLocation(), diag::note_previous_access_declaration)
      42                4:       << PrevMemberDecl << PrevMemberDecl->getAccess();
      43                 : 
      44                4:     MemberDecl->setAccess(LexicalAS);
      45                4:     return true;
      46                 :   }
      47                 : 
      48              159:   MemberDecl->setAccess(PrevMemberDecl->getAccess());
      49              159:   return false;
      50                 : }
      51                 : 
      52                 : /// Find a class on the derivation path between Derived and Base that is
      53                 : /// inaccessible. If @p NoPrivileges is true, special access rights (members
      54                 : /// and friends) are not considered.
      55                 : const CXXBaseSpecifier *Sema::FindInaccessibleBase(
      56               87:     QualType Derived, QualType Base, CXXBasePaths &Paths, bool NoPrivileges) {
      57               87:   Base = Context.getCanonicalType(Base).getUnqualifiedType();
      58                 :   assert(!Paths.isAmbiguous(Base) &&
                       87: branch 1 taken
                        0: branch 2 not taken
      59               87:          "Can't check base class access if set of paths is ambiguous");
      60                 :   assert(Paths.isRecordingPaths() &&
                       87: branch 1 taken
                        0: branch 2 not taken
      61               87:          "Can't check base class access without recorded paths");
      62                 : 
      63                 : 
      64               87:   const CXXBaseSpecifier *InaccessibleBase = 0;
      65                 : 
      66               87:   const CXXRecordDecl *CurrentClassDecl = 0;
                       25: branch 2 taken
                       62: branch 3 taken
      67               87:   if (CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(getCurFunctionDecl()))
      68               25:     CurrentClassDecl = MD->getParent();
      69                 : 
                       88: branch 4 taken
                       19: branch 5 taken
      70              107:   for (CXXBasePaths::paths_iterator Path = Paths.begin(), PathsEnd = Paths.end();
      71                 :       Path != PathsEnd; ++Path) {
      72                 : 
      73               88:     bool FoundInaccessibleBase = false;
      74                 : 
                       98: branch 2 taken
                       68: branch 3 taken
      75              254:     for (CXXBasePath::const_iterator Element = Path->begin(),
      76               88:          ElementEnd = Path->end(); Element != ElementEnd; ++Element) {
      77               98:       const CXXBaseSpecifier *Base = Element->Base;
      78                 : 
                        0: branch 1 not taken
                       56: branch 2 taken
                       30: branch 3 taken
                       12: branch 4 taken
      79               98:       switch (Base->getAccessSpecifier()) {
      80                 :       default:
      81                0:         assert(0 && "invalid access specifier");
      82                 :       case AS_public:
      83                 :         // Nothing to do.
      84               56:         break;
      85                 :       case AS_private:
      86                 :         // FIXME: Check if the current function/class is a friend.
                       29: branch 0 taken
                        1: branch 1 taken
                       19: branch 2 taken
                       10: branch 3 taken
      87               30:         if (NoPrivileges || CurrentClassDecl != Element->Class)
      88               20:           FoundInaccessibleBase = true;
      89                 :         break;
      90                 :       case AS_protected:
      91                 :         // FIXME: Implement
      92                 :         break;
      93                 :       }
      94                 : 
                       20: branch 0 taken
                       78: branch 1 taken
      95               98:       if (FoundInaccessibleBase) {
      96               20:         InaccessibleBase = Base;
      97               20:         break;
      98                 :       }
      99                 :     }
     100                 : 
                       68: branch 0 taken
                       20: branch 1 taken
     101               88:     if (!FoundInaccessibleBase) {
     102                 :       // We found a path to the base, our work here is done.
     103               68:       return 0;
     104                 :     }
     105                 :   }
     106                 : 
                        0: branch 0 not taken
                       19: branch 1 taken
     107               19:   assert(InaccessibleBase && "no path found, but no inaccessible base");
     108               19:   return InaccessibleBase;
     109                 : }
     110                 : 
     111                 : /// CheckBaseClassAccess - Check that a derived class can access its base class
     112                 : /// and report an error if it can't. [class.access.base]
     113                 : bool Sema::CheckBaseClassAccess(QualType Derived, QualType Base,
     114                 :                                 unsigned InaccessibleBaseID,
     115                 :                                 CXXBasePaths &Paths, SourceLocation AccessLoc,
     116              318:                                 DeclarationName Name) {
     117                 : 
                      237: branch 1 taken
                       81: branch 2 taken
     118              318:   if (!getLangOptions().AccessControl)
     119              237:     return false;
     120                 :   const CXXBaseSpecifier *InaccessibleBase = FindInaccessibleBase(
     121               81:                                                Derived, Base, Paths);
     122                 : 
                       18: branch 0 taken
                       63: branch 1 taken
     123               81:   if (InaccessibleBase) {
     124                 :     Diag(AccessLoc, InaccessibleBaseID)
     125               18:       << Derived << Base << Name;
     126                 : 
     127               18:     AccessSpecifier AS = InaccessibleBase->getAccessSpecifierAsWritten();
     128                 : 
     129                 :     // If there's no written access specifier, then the inheritance specifier
     130                 :     // is implicitly private.
                        1: branch 0 taken
                       17: branch 1 taken
     131               18:     if (AS == AS_none)
     132                 :       Diag(InaccessibleBase->getSourceRange().getBegin(),
     133                1:            diag::note_inheritance_implicitly_private_here);
     134                 :     else
     135                 :       Diag(InaccessibleBase->getSourceRange().getBegin(),
     136               17:            diag::note_inheritance_specifier_here) << AS;
     137                 : 
     138               18:     return true;
     139                 :   }
     140                 : 
     141               63:   return false;
     142                 : }
     143                 : 
     144                 : /// Diagnose the path which caused the given declaration to become
     145                 : /// inaccessible.
     146                 : static void DiagnoseAccessPath(Sema &S, const LookupResult &R, NamedDecl *D,
     147               76:                                AccessSpecifier Access) {
     148                 :   // Easy case: the decl's natural access determined its path access.
                       32: branch 1 taken
                       44: branch 2 taken
                       14: branch 4 taken
                       18: branch 5 taken
                       58: branch 6 taken
                       18: branch 7 taken
     149               76:   if (Access == D->getAccess() || D->getAccess() == AS_private) {
     150                 :     S.Diag(D->getLocation(), diag::note_access_natural)
     151               58:       << (unsigned) (Access == AS_protected);
     152               58:     return;
     153                 :   }
     154                 : 
     155                 :   // TODO: flesh this out
     156                 :   S.Diag(D->getLocation(), diag::note_access_constrained_by_path)
     157               18:     << (unsigned) (Access == AS_protected);
     158                 : }
     159                 : 
     160                 : /// Checks access to the given declaration in the current context.
     161                 : ///
     162                 : /// \param R the means via which the access was made; must have a naming
     163                 : ///   class set
     164                 : /// \param D the declaration accessed
     165                 : /// \param Access the best access along any inheritance path from the
     166                 : ///   naming class to the declaration.  AS_none means the path is impossible
     167                 : bool Sema::CheckAccess(const LookupResult &R, NamedDecl *D,
     168              239:                        AccessSpecifier Access) {
                      239: branch 1 taken
                        0: branch 2 not taken
     169              239:   assert(R.getNamingClass() && "performing access check without naming class");
     170                 : 
     171                 :   // If the access path is public, it's accessible everywhere.
                      129: branch 0 taken
                      110: branch 1 taken
     172              239:   if (Access == AS_public)
     173              129:     return false;
     174                 : 
     175                 :   // If we're currently parsing a top-level declaration, delay
     176                 :   // diagnostics.  This is the only case where parsing a declaration
     177                 :   // can actually change our effective context for the purposes of
     178                 :   // access control.
                        6: branch 1 taken
                      104: branch 2 taken
                        6: branch 3 taken
                        0: branch 4 not taken
                        6: branch 5 taken
                      104: branch 6 taken
     179              110:   if (CurContext->isFileContext() && ParsingDeclDepth) {
     180                 :     DelayedDiagnostics.push_back(
     181                 :         DelayedDiagnostic::makeAccess(R.getNameLoc(), D, Access,
     182                6:                                       R.getNamingClass()));
     183                6:     return false;
     184                 :   }
     185                 : 
     186              104:   return CheckEffectiveAccess(CurContext, R, D, Access);
     187                 : }
     188                 : 
     189                 : /// Checks access from the given effective context.
     190                 : bool Sema::CheckEffectiveAccess(DeclContext *EffectiveContext,
     191                 :                                 const LookupResult &R,
     192              110:                                 NamedDecl *D, AccessSpecifier Access) {
     193              110:   DeclContext *DC = EffectiveContext;
                        3: branch 1 taken
                      107: branch 2 taken
                        0: branch 5 not taken
                        3: branch 6 taken
                        0: branch 7 not taken
                      110: branch 8 taken
     194              220:   while (isa<CXXRecordDecl>(DC) &&
     195                 :          cast<CXXRecordDecl>(DC)->isAnonymousStructOrUnion())
     196                0:     DC = DC->getParent();
     197                 : 
     198                 :   CXXRecordDecl *CurRecord;
                        3: branch 1 taken
                      107: branch 2 taken
     199              110:   if (isa<CXXRecordDecl>(DC))
     200                3:     CurRecord = cast<CXXRecordDecl>(DC);
                       45: branch 1 taken
                       62: branch 2 taken
     201              107:   else if (isa<CXXMethodDecl>(DC))
     202               45:     CurRecord = cast<CXXMethodDecl>(DC)->getParent();
     203                 :   else {
     204                 :     Diag(R.getNameLoc(), diag::err_access_outside_class)
     205               62:       << (Access == AS_protected);
     206               62:     DiagnoseAccessPath(*this, R, D, Access);
     207               62:     return true;
     208                 :   }
     209                 : 
     210               48:   CXXRecordDecl *NamingClass = R.getNamingClass();
                        0: branch 1 not taken
                       48: branch 2 taken
     211               96:   while (NamingClass->isAnonymousStructOrUnion())
     212                 :     // This should be guaranteed by the fact that the decl has
     213                 :     // non-public access.  If not, we should make it guaranteed!
     214                0:     NamingClass = cast<CXXRecordDecl>(NamingClass);
     215                 : 
     216                 :   // White-list accesses from within the declaring class.
                       40: branch 0 taken
                        8: branch 1 taken
                       28: branch 4 taken
                       12: branch 5 taken
                       28: branch 6 taken
                       20: branch 7 taken
     217               48:   if (Access != AS_none &&
     218                 :       CurRecord->getCanonicalDecl() == NamingClass->getCanonicalDecl())
     219               28:     return false;
     220                 : 
     221                 :   // Protected access.
                        6: branch 0 taken
                       14: branch 1 taken
     222               20:   if (Access == AS_protected) {
     223                 :     // FIXME: implement [class.protected]p1
                        6: branch 1 taken
                        0: branch 2 not taken
     224                6:     if (CurRecord->isDerivedFrom(NamingClass))
     225                6:       return false;
     226                 : 
     227                 :     // FIXME: dependent classes
     228                 :   }
     229                 : 
     230                 :   // FIXME: friends
     231                 : 
     232                 :   // Okay, it's a bad access, reject it.
     233                 : 
     234                 :   
     235               14:   CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(D->getDeclContext());
     236                 : 
                        0: branch 0 not taken
                       14: branch 1 taken
     237               14:   if (Access == AS_protected) {
     238                 :     Diag(R.getNameLoc(), diag::err_access_protected)
     239                 :       << Context.getTypeDeclType(DeclaringClass)
     240                0:       << Context.getTypeDeclType(CurRecord);
     241                0:     DiagnoseAccessPath(*this, R, D, Access);
     242                0:     return true;
     243                 :   }
     244                 : 
                        8: branch 0 taken
                        6: branch 1 taken
                        0: branch 2 not taken
                        8: branch 3 taken
     245               14:   assert(Access == AS_private || Access == AS_none);
     246                 :   Diag(R.getNameLoc(), diag::err_access_private)
     247                 :     << Context.getTypeDeclType(DeclaringClass)
     248               14:     << Context.getTypeDeclType(CurRecord);
     249               14:   DiagnoseAccessPath(*this, R, D, Access);
     250               14:   return true;
     251                 : }
     252                 : 
     253                6: void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *Ctx) {
     254                6:   NamedDecl *D = DD.AccessData.Decl;
     255                 : 
     256                 :   // Fake up a lookup result.
     257                6:   LookupResult R(*this, D->getDeclName(), DD.Loc, LookupOrdinaryName);
     258                6:   R.suppressDiagnostics();
     259                6:   R.setNamingClass(DD.AccessData.NamingClass);
     260                 : 
     261                 :   // Pretend we did this from the context of the newly-parsed
     262                 :   // declaration.
     263                6:   DeclContext *EffectiveContext = Ctx->getDeclContext();
     264                 : 
                        3: branch 1 taken
                        3: branch 2 taken
     265                6:   if (CheckEffectiveAccess(EffectiveContext, R, D, DD.AccessData.Access))
     266                3:     DD.Triggered = true;
     267                6: }
     268                 : 
     269                 : bool Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E,
     270             1315:                                        NamedDecl *D, AccessSpecifier Access) {
                        9: branch 1 taken
                     1306: branch 2 taken
                        6: branch 4 taken
                        3: branch 5 taken
                     1312: branch 6 taken
                        3: branch 7 taken
     271             1315:   if (!getLangOptions().AccessControl || !E->getNamingClass())
     272             1312:     return false;
     273                 : 
     274                 :   // Fake up a lookup result.
     275                3:   LookupResult R(*this, E->getName(), E->getNameLoc(), LookupOrdinaryName);
     276                3:   R.suppressDiagnostics();
     277                 : 
     278                3:   R.setNamingClass(E->getNamingClass());
     279                3:   R.addDecl(D, Access);
     280                 : 
     281                 :   // FIXME: protected check (triggers for member-address expressions)
     282                 : 
     283                3:   return CheckAccess(R, D, Access);
     284                 : }
     285                 : 
     286                 : /// Perform access-control checking on a previously-unresolved member
     287                 : /// access which has now been resolved to a member.
     288                 : bool Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E,
     289              160:                                        NamedDecl *D, AccessSpecifier Access) {
                      147: branch 1 taken
                       13: branch 2 taken
     290              160:   if (!getLangOptions().AccessControl)
     291              147:     return false;
     292                 : 
     293                 :   // Fake up a lookup result.
     294                 :   LookupResult R(*this, E->getMemberName(), E->getMemberLoc(),
     295               13:                  LookupOrdinaryName);
     296               13:   R.suppressDiagnostics();
     297                 : 
     298               13:   R.setNamingClass(E->getNamingClass());
     299               13:   R.addDecl(D, Access);
     300                 : 
                        2: branch 1 taken
                       11: branch 2 taken
     301               13:   if (CheckAccess(R, D, Access))
     302                2:     return true;
     303                 : 
     304                 :   // FIXME: protected check
     305                 : 
     306               11:   return false;
     307                 : }
     308                 : 
     309              106: bool Sema::CheckDestructorAccess(SourceLocation Loc, const RecordType *RT) {
                      101: branch 1 taken
                        5: branch 2 taken
     310              106:   if (!getLangOptions().AccessControl)
     311              101:     return false;
     312                 : 
     313                5:   CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl());
     314                5:   CXXDestructorDecl *Dtor = NamingClass->getDestructor(Context);
     315                 : 
     316                5:   AccessSpecifier Access = Dtor->getAccess();
                        1: branch 0 taken
                        4: branch 1 taken
     317                5:   if (Access == AS_public)
     318                1:     return false;
     319                 : 
     320                4:   LookupResult R(*this, Dtor->getDeclName(), Loc, LookupOrdinaryName);
     321                4:   R.suppressDiagnostics();
     322                 : 
     323                4:   R.setNamingClass(NamingClass);
     324                4:   return CheckAccess(R, Dtor, Access);
     325                 : 
     326                 :   // FIXME: protected check
     327                 : }
     328                 : 
     329                 : /// Checks access to a constructor.
     330                 : bool Sema::CheckConstructorAccess(SourceLocation UseLoc,
     331                 :                                   CXXConstructorDecl *Constructor,
     332             1820:                                   AccessSpecifier Access) {
                     1764: branch 1 taken
                       56: branch 2 taken
     333             1820:   if (!getLangOptions().AccessControl)
     334             1764:     return false;
     335                 : 
     336               56:   CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(Constructor->getParent());
     337                 : 
     338               56:   LookupResult R(*this, Constructor->getDeclName(), UseLoc, LookupOrdinaryName);
     339               56:   R.suppressDiagnostics();
     340                 : 
     341               56:   R.setNamingClass(NamingClass);
     342               56:   return CheckAccess(R, Constructor, Access);
     343                 : }
     344                 : 
     345                 : /// Checks access to an overloaded member operator, including
     346                 : /// conversion operators.
     347                 : bool Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
     348                 :                                      Expr *ObjectExpr,
     349                 :                                      NamedDecl *MemberOperator,
     350              242:                                      AccessSpecifier Access) {
                      222: branch 1 taken
                       20: branch 2 taken
     351              242:   if (!getLangOptions().AccessControl)
     352              222:     return false;
     353                 : 
     354               20:   const RecordType *RT = ObjectExpr->getType()->getAs<RecordType>();
                        0: branch 0 not taken
                       20: branch 1 taken
     355               20:   assert(RT && "found member operator but object expr not of record type");
     356               20:   CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl());
     357                 : 
     358               20:   LookupResult R(*this, DeclarationName(), OpLoc, LookupOrdinaryName);
     359               20:   R.suppressDiagnostics();
     360                 : 
     361               20:   R.setNamingClass(NamingClass);
                       11: branch 1 taken
                        9: branch 2 taken
     362               20:   if (CheckAccess(R, MemberOperator, Access))
     363               11:     return true;
     364                 : 
     365                 :   // FIXME: protected check
     366                 : 
     367                9:   return false;
     368                 : }
     369                 : 
     370                 : /// Checks access to all the declarations in the given result set.
     371              143: void Sema::CheckAccess(const LookupResult &R) {
                      143: branch 4 taken
                      143: branch 5 taken
     372              286:   for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I)
     373              143:     CheckAccess(R, *I, I.getAccess());
     374              143: }

Generated: 2010-02-10 01:31 by zcov