zcov: / lib/AST/CXXInheritance.cpp


Files: 1 Branches Taken: 79.5% 70 / 88
Generated: 2010-02-10 01:31 Branches Executed: 95.5% 84 / 88
Line Coverage: 93.3% 140 / 150


Programs: 2 Runs 3018


       1                 : //===------ CXXInheritance.cpp - C++ Inheritance ----------------*- 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 routines that help analyzing C++ inheritance hierarchies.
      11                 : //
      12                 : //===----------------------------------------------------------------------===//
      13                 : #include "clang/AST/CXXInheritance.h"
      14                 : #include "clang/AST/DeclCXX.h"
      15                 : #include <algorithm>
      16                 : #include <set>
      17                 : 
      18                 : using namespace clang;
      19                 : 
      20                 : /// \brief Computes the set of declarations referenced by these base
      21                 : /// paths.
      22              157: void CXXBasePaths::ComputeDeclsFound() {
      23                 :   assert(NumDeclsFound == 0 && !DeclsFound &&
                      157: branch 0 taken
                        0: branch 1 not taken
                        0: branch 2 not taken
                      157: branch 3 taken
      24              157:          "Already computed the set of declarations");
      25                 :   
      26              157:   std::set<NamedDecl *> Decls;
                      163: branch 4 taken
                      157: branch 5 taken
      27              320:   for (CXXBasePaths::paths_iterator Path = begin(), PathEnd = end();
      28                 :        Path != PathEnd; ++Path)
      29              163:     Decls.insert(*Path->Decls.first);
      30                 :   
      31              157:   NumDeclsFound = Decls.size();
      32              157:   DeclsFound = new NamedDecl * [NumDeclsFound];
      33              157:   std::copy(Decls.begin(), Decls.end(), DeclsFound);
      34              157: }
      35                 : 
      36              157: CXXBasePaths::decl_iterator CXXBasePaths::found_decls_begin() {
                      157: branch 0 taken
                        0: branch 1 not taken
      37              157:   if (NumDeclsFound == 0)
      38              157:     ComputeDeclsFound();
      39              157:   return DeclsFound;
      40                 : }
      41                 : 
      42              157: CXXBasePaths::decl_iterator CXXBasePaths::found_decls_end() {
                        0: branch 0 not taken
                      157: branch 1 taken
      43              157:   if (NumDeclsFound == 0)
      44                0:     ComputeDeclsFound();
      45              157:   return DeclsFound + NumDeclsFound;
      46                 : }
      47                 : 
      48                 : /// isAmbiguous - Determines whether the set of paths provided is
      49                 : /// ambiguous, i.e., there are two or more paths that refer to
      50                 : /// different base class subobjects of the same type. BaseType must be
      51                 : /// an unqualified, canonical class type.
      52              528: bool CXXBasePaths::isAmbiguous(QualType BaseType) {
                      528: branch 1 taken
                        0: branch 2 not taken
      53              528:   assert(BaseType.isCanonical() && "Base type must be the canonical type");
                      528: branch 1 taken
                        0: branch 2 not taken
      54              528:   assert(BaseType.hasQualifiers() == 0 && "Base type must be unqualified");
      55              528:   std::pair<bool, unsigned>& Subobjects = ClassSubobjects[BaseType];
                       39: branch 0 taken
                      489: branch 1 taken
      56              567:   return Subobjects.second + (Subobjects.first? 1 : 0) > 1;
      57                 : }
      58                 : 
      59                 : /// clear - Clear out all prior path information.
      60               35: void CXXBasePaths::clear() {
      61               35:   Paths.clear();
      62               35:   ClassSubobjects.clear();
      63               35:   ScratchPath.clear();
      64               35:   DetectedVirtual = 0;
      65               35: }
      66                 : 
      67                 : /// @brief Swaps the contents of this CXXBasePaths structure with the
      68                 : /// contents of Other.
      69               30: void CXXBasePaths::swap(CXXBasePaths &Other) {
      70               30:   std::swap(Origin, Other.Origin);
      71               30:   Paths.swap(Other.Paths);
      72               30:   ClassSubobjects.swap(Other.ClassSubobjects);
      73               30:   std::swap(FindAmbiguities, Other.FindAmbiguities);
      74               30:   std::swap(RecordPaths, Other.RecordPaths);
      75               30:   std::swap(DetectVirtual, Other.DetectVirtual);
      76               30:   std::swap(DetectedVirtual, Other.DetectedVirtual);
      77               30: }
      78                 : 
      79             2518: bool CXXRecordDecl::isDerivedFrom(CXXRecordDecl *Base) const {
      80                 :   CXXBasePaths Paths(/*FindAmbiguities=*/false, /*RecordPaths=*/false,
      81             2518:                      /*DetectVirtual=*/false);
      82             2518:   return isDerivedFrom(Base, Paths);
      83                 : }
      84                 : 
      85             3596: bool CXXRecordDecl::isDerivedFrom(CXXRecordDecl *Base, CXXBasePaths &Paths) const {
                      123: branch 2 taken
                     3473: branch 3 taken
      86             3596:   if (getCanonicalDecl() == Base->getCanonicalDecl())
      87              123:     return false;
      88                 :   
      89             3473:   Paths.setOrigin(const_cast<CXXRecordDecl*>(this));
      90             3473:   return lookupInBases(&FindBaseClass, Base->getCanonicalDecl(), Paths);
      91                 : }
      92                 : 
      93               67: static bool BaseIsNot(const CXXRecordDecl *Base, void *OpaqueTarget) {
      94                 :   // OpaqueTarget is a CXXRecordDecl*.
      95               67:   return Base->getCanonicalDecl() != (const CXXRecordDecl*) OpaqueTarget;
      96                 : }
      97                 : 
      98               66: bool CXXRecordDecl::isProvablyNotDerivedFrom(const CXXRecordDecl *Base) const {
      99               66:   return forallBases(BaseIsNot, (void*) Base->getCanonicalDecl());
     100                 : }
     101                 : 
     102                 : bool CXXRecordDecl::forallBases(ForallBasesCallback *BaseMatches,
     103                 :                                 void *OpaqueData,
     104              147:                                 bool AllowShortCircuit) const {
     105              147:   ASTContext &Context = getASTContext();
     106              147:   llvm::SmallVector<const CXXRecordDecl*, 8> Queue;
     107                 : 
     108              147:   const CXXRecordDecl *Record = this;
     109              147:   bool AllMatches = true;
     110               64:   while (true) {
                      139: branch 0 taken
                      137: branch 1 taken
     111              276:     for (CXXRecordDecl::base_class_const_iterator
     112              211:            I = Record->bases_begin(), E = Record->bases_end(); I != E; ++I) {
     113              139:       const RecordType *Ty = I->getType()->getAs<RecordType>();
                       11: branch 0 taken
                      128: branch 1 taken
     114              139:       if (!Ty) {
                       11: branch 0 taken
                        0: branch 1 not taken
     115               11:         if (AllowShortCircuit) return false;
     116                0:         AllMatches = false;
     117                0:         continue;
     118                 :       }
     119                 : 
     120                 :       CXXRecordDecl *Base = 
     121              128:             cast_or_null<CXXRecordDecl>(Ty->getDecl()->getDefinition(Context));
                        0: branch 0 not taken
                      128: branch 1 taken
     122              128:       if (!Base) {
                        0: branch 0 not taken
                        0: branch 1 not taken
     123                0:         if (AllowShortCircuit) return false;
     124                0:         AllMatches = false;
     125                0:         continue;
     126                 :       }
     127                 :       
     128              128:       Queue.push_back(Base);
                       63: branch 1 taken
                       65: branch 2 taken
     129              128:       if (!BaseMatches(Base, OpaqueData)) {
                       63: branch 0 taken
                        0: branch 1 not taken
     130               63:         if (AllowShortCircuit) return false;
     131                0:         AllMatches = false;
     132                0:         continue;
     133                 :       }
     134                 :     }
     135                 : 
                       64: branch 1 taken
                       73: branch 2 taken
     136              137:     if (Queue.empty()) break;
     137               64:     Record = Queue.back(); // not actually a queue.
     138               64:     Queue.pop_back();
     139                 :   }
     140                 : 
     141               73:   return AllMatches;
     142                 : }
     143                 : 
     144                 : bool CXXRecordDecl::lookupInBases(BaseMatchesCallback *BaseMatches,
     145                 :                                   void *UserData,
     146            26568:                                   CXXBasePaths &Paths) const {
     147            26568:   bool FoundPath = false;
     148                 : 
     149                 :   // The access of the path down to this record.
     150            26568:   AccessSpecifier AccessToHere = Paths.ScratchPath.Access;
     151            26568:   bool IsFirstStep = Paths.ScratchPath.empty();
     152                 : 
     153            26568:   ASTContext &Context = getASTContext();
                     9510: branch 1 taken
                    25236: branch 2 taken
     154            61314:   for (base_class_const_iterator BaseSpec = bases_begin(),
     155            26568:          BaseSpecEnd = bases_end(); BaseSpec != BaseSpecEnd; ++BaseSpec) {
     156                 :     // Find the record of the base class subobjects for this type.
     157                 :     QualType BaseType = Context.getCanonicalType(BaseSpec->getType())
     158             9510:                                                           .getUnqualifiedType();
     159                 :     
     160                 :     // C++ [temp.dep]p3:
     161                 :     //   In the definition of a class template or a member of a class template,
     162                 :     //   if a base class of the class template depends on a template-parameter,
     163                 :     //   the base class scope is not examined during unqualified name lookup 
     164                 :     //   either at the point of definition of the class template or member or 
     165                 :     //   during an instantiation of the class tem- plate or member.
                      222: branch 2 taken
                     9288: branch 3 taken
     166             9510:     if (BaseType->isDependentType())
     167              222:       continue;
     168                 :     
     169                 :     // Determine whether we need to visit this base class at all,
     170                 :     // updating the count of subobjects appropriately.
     171             9288:     std::pair<bool, unsigned>& Subobjects = Paths.ClassSubobjects[BaseType];
     172             9288:     bool VisitBase = true;
     173             9288:     bool SetVirtual = false;
                     1848: branch 1 taken
                     7440: branch 2 taken
     174             9288:     if (BaseSpec->isVirtual()) {
     175             1848:       VisitBase = !Subobjects.first;
     176             1848:       Subobjects.first = true;
                     1503: branch 1 taken
                      345: branch 2 taken
                     1103: branch 3 taken
                      400: branch 4 taken
                     1103: branch 5 taken
                      745: branch 6 taken
     177             1848:       if (Paths.isDetectingVirtual() && Paths.DetectedVirtual == 0) {
     178                 :         // If this is the first virtual we find, remember it. If it turns out
     179                 :         // there is no base path here, we'll reset it later.
     180             1103:         Paths.DetectedVirtual = BaseType->getAs<RecordType>();
     181             1103:         SetVirtual = true;
     182                 :       }
     183                 :     } else
     184             7440:       ++Subobjects.second;
     185                 :     
                     7663: branch 1 taken
                     1625: branch 2 taken
     186             9288:     if (Paths.isRecordingPaths()) {
     187                 :       // Add this base specifier to the current path.
     188                 :       CXXBasePathElement Element;
     189             7663:       Element.Base = &*BaseSpec;
     190             7663:       Element.Class = this;
                     1752: branch 1 taken
                     5911: branch 2 taken
     191             7663:       if (BaseSpec->isVirtual())
     192             1752:         Element.SubobjectNumber = 0;
     193                 :       else
     194             5911:         Element.SubobjectNumber = Subobjects.second;
     195             7663:       Paths.ScratchPath.push_back(Element);
     196                 : 
     197                 :       // Calculate the "top-down" access to this base class.
     198                 :       // The spec actually describes this bottom-up, but top-down is
     199                 :       // equivalent because the definition works out as follows:
     200                 :       // 1. Write down the access along each step in the inheritance
     201                 :       //    chain, followed by the access of the decl itself.
     202                 :       //    For example, in
     203                 :       //      class A { public: int foo; };
     204                 :       //      class B : protected A {};
     205                 :       //      class C : public B {};
     206                 :       //      class D : private C {};
     207                 :       //    we would write:
     208                 :       //      private public protected public
     209                 :       // 2. If 'private' appears anywhere except far-left, access is denied.
     210                 :       // 3. Otherwise, overall access is determined by the most restrictive
     211                 :       //    access in the sequence.
                     5395: branch 0 taken
                     2268: branch 1 taken
     212             7663:       if (IsFirstStep)
     213             5395:         Paths.ScratchPath.Access = BaseSpec->getAccessSpecifier();
     214                 :       else
     215                 :         Paths.ScratchPath.Access
     216             2268:           = MergeAccess(AccessToHere, BaseSpec->getAccessSpecifier());
     217                 :     }
     218                 :     
     219                 :     // Track whether there's a path involving this specific base.
     220             9288:     bool FoundPathThroughBase = false;
     221                 :     
                     2801: branch 1 taken
                     6487: branch 2 taken
     222             9288:     if (BaseMatches(BaseSpec, Paths.ScratchPath, UserData)) {
     223                 :       // We've found a path that terminates at this base.
     224             2801:       FoundPath = FoundPathThroughBase = true;
                     1720: branch 1 taken
                     1081: branch 2 taken
     225             2801:       if (Paths.isRecordingPaths()) {
     226                 :         // We have a path. Make a copy of it before moving on.
     227             1720:         Paths.Paths.push_back(Paths.ScratchPath);
                      992: branch 1 taken
                       89: branch 2 taken
     228             1081:       } else if (!Paths.isFindingAmbiguities()) {
     229                 :         // We found a path and we don't care about ambiguities;
     230                 :         // return immediately.
     231              992:         return FoundPath;
     232                 :       }
                     6346: branch 0 taken
                      141: branch 1 taken
     233             6487:     } else if (VisitBase) {
     234                 :       CXXRecordDecl *BaseRecord
     235                 :         = cast<CXXRecordDecl>(BaseSpec->getType()->getAs<RecordType>()
     236             6346:                                 ->getDecl());
                      746: branch 1 taken
                     5600: branch 2 taken
     237             6346:       if (BaseRecord->lookupInBases(BaseMatches, UserData, Paths)) {
     238                 :         // C++ [class.member.lookup]p2:
     239                 :         //   A member name f in one sub-object B hides a member name f in
     240                 :         //   a sub-object A if A is a base class sub-object of B. Any
     241                 :         //   declarations that are so hidden are eliminated from
     242                 :         //   consideration.
     243                 :         
     244                 :         // There is a path to a base class that meets the criteria. If we're 
     245                 :         // not collecting paths or finding ambiguities, we're done.
     246              746:         FoundPath = FoundPathThroughBase = true;
                      340: branch 1 taken
                      406: branch 2 taken
     247              746:         if (!Paths.isFindingAmbiguities())
     248              340:           return FoundPath;
     249                 :       }
     250                 :     }
     251                 :     
     252                 :     // Pop this base specifier off the current path (if we're
     253                 :     // collecting paths).
                     7513: branch 1 taken
                      443: branch 2 taken
     254             7956:     if (Paths.isRecordingPaths()) {
     255             7513:       Paths.ScratchPath.pop_back();
     256                 :     }
     257                 : 
     258                 :     // If we set a virtual earlier, and this isn't a path, forget it again.
                     1045: branch 0 taken
                     6911: branch 1 taken
                      835: branch 2 taken
                      210: branch 3 taken
     259             7956:     if (SetVirtual && !FoundPathThroughBase) {
     260              835:       Paths.DetectedVirtual = 0;
     261                 :     }
     262                 :   }
     263                 : 
     264                 :   // Reset the scratch path access.
     265            25236:   Paths.ScratchPath.Access = AccessToHere;
     266                 :   
     267            25236:   return FoundPath;
     268                 : }
     269                 : 
     270                 : bool CXXRecordDecl::FindBaseClass(const CXXBaseSpecifier *Specifier, 
     271                 :                                   CXXBasePath &Path,
     272             3842:                                   void *BaseRecord) {
     273                 :   assert(((Decl *)BaseRecord)->getCanonicalDecl() == BaseRecord &&
                     3842: branch 1 taken
                        0: branch 2 not taken
     274             3842:          "User data for FindBaseClass is not canonical!");
     275                 :   return Specifier->getType()->getAs<RecordType>()->getDecl()
     276             3842:            ->getCanonicalDecl() == BaseRecord;
     277                 : }
     278                 : 
     279                 : bool CXXRecordDecl::FindTagMember(const CXXBaseSpecifier *Specifier, 
     280                 :                                   CXXBasePath &Path,
     281                6:                                   void *Name) {
     282                6:   RecordDecl *BaseRecord = Specifier->getType()->getAs<RecordType>()->getDecl();
     283                 : 
     284                6:   DeclarationName N = DeclarationName::getFromOpaquePtr(Name);
                        0: branch 1 not taken
                        6: branch 2 taken
     285                6:   for (Path.Decls = BaseRecord->lookup(N);
     286                 :        Path.Decls.first != Path.Decls.second;
     287                 :        ++Path.Decls.first) {
                        0: branch 1 not taken
                        0: branch 2 not taken
     288                0:     if ((*Path.Decls.first)->isInIdentifierNamespace(IDNS_Tag))
     289                0:       return true;
     290                 :   }
     291                 : 
     292                6:   return false;
     293                 : }
     294                 : 
     295                 : bool CXXRecordDecl::FindOrdinaryMember(const CXXBaseSpecifier *Specifier, 
     296                 :                                        CXXBasePath &Path,
     297             1429:                                        void *Name) {
     298             1429:   RecordDecl *BaseRecord = Specifier->getType()->getAs<RecordType>()->getDecl();
     299                 :   
     300             1429:   const unsigned IDNS = IDNS_Ordinary | IDNS_Tag | IDNS_Member;
     301             1429:   DeclarationName N = DeclarationName::getFromOpaquePtr(Name);
                      422: branch 1 taken
                     1010: branch 2 taken
     302             1432:   for (Path.Decls = BaseRecord->lookup(N);
     303                 :        Path.Decls.first != Path.Decls.second;
     304                 :        ++Path.Decls.first) {
                      419: branch 1 taken
                        3: branch 2 taken
     305              422:     if ((*Path.Decls.first)->isInIdentifierNamespace(IDNS))
     306              419:       return true;
     307                 :   }
     308                 :   
     309             1010:   return false;
     310                 : }
     311                 : 
     312                 : bool CXXRecordDecl::
     313                 : FindNestedNameSpecifierMember(const CXXBaseSpecifier *Specifier, 
     314                 :                               CXXBasePath &Path,
     315              157:                               void *Name) {
     316              157:   RecordDecl *BaseRecord = Specifier->getType()->getAs<RecordType>()->getDecl();
     317                 :   
     318              157:   DeclarationName N = DeclarationName::getFromOpaquePtr(Name);
                      105: branch 1 taken
                       52: branch 2 taken
     319              157:   for (Path.Decls = BaseRecord->lookup(N);
     320                 :        Path.Decls.first != Path.Decls.second;
     321                 :        ++Path.Decls.first) {
     322                 :     // FIXME: Refactor the "is it a nested-name-specifier?" check
                      105: branch 1 taken
                        0: branch 2 not taken
                      105: branch 4 taken
                        0: branch 5 not taken
                      105: branch 6 taken
                        0: branch 7 not taken
     323              105:     if (isa<TypedefDecl>(*Path.Decls.first) ||
     324                 :         (*Path.Decls.first)->isInIdentifierNamespace(IDNS_Tag))
     325              105:       return true;
     326                 :   }
     327                 :   
     328               52:   return false;
     329                 : }

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