zcov: / lib/Checker/CocoaConventions.cpp


Files: 1 Branches Taken: 88.7% 94 / 106
Generated: 2010-02-10 01:31 Branches Executed: 100.0% 106 / 106
Line Coverage: 97.5% 79 / 81


Programs: 1 Runs 2897


       1                 : //===- CocoaConventions.h - Special handling of Cocoa conventions -*- 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 defines 
      11                 : //
      12                 : //===----------------------------------------------------------------------===//
      13                 : 
      14                 : #include "clang/Checker/DomainSpecific/CocoaConventions.h"
      15                 : #include "clang/AST/Type.h"
      16                 : #include "clang/AST/Decl.h"
      17                 : #include "clang/AST/DeclObjC.h"
      18                 : #include "llvm/ADT/StringExtras.h"
      19                 : 
      20                 : using namespace clang;
      21                 : 
      22                 : using llvm::StringRef;
      23                 : 
      24                 : // The "fundamental rule" for naming conventions of methods:
      25                 : //  (url broken into two lines)
      26                 : //  http://developer.apple.com/documentation/Cocoa/Conceptual/
      27                 : //     MemoryMgmt/Tasks/MemoryManagementRules.html
      28                 : //
      29                 : // "You take ownership of an object if you create it using a method whose name
      30                 : //  begins with "alloc" or "new" or contains "copy" (for example, alloc,
      31                 : //  newObject, or mutableCopy), or if you send it a retain message. You are
      32                 : //  responsible for relinquishing ownership of objects you own using release
      33                 : //  or autorelease. Any other time you receive an object, you must
      34                 : //  not release it."
      35                 : //
      36                 : 
      37             6880: static bool isWordEnd(char ch, char prev, char next) {
      38                 :   return ch == '\0'
      39                 :       || (islower(prev) && isupper(ch)) // xxxC
      40                 :       || (isupper(prev) && isupper(ch) && islower(next)) // XXCreate
                     6462: branch 0 taken
                      418: branch 1 taken
                     4482: branch 3 taken
                     1980: branch 4 taken
                     3815: branch 6 taken
                      667: branch 7 taken
                      803: branch 9 taken
                     4992: branch 10 taken
                      142: branch 12 taken
                      661: branch 13 taken
                       98: branch 15 taken
                       44: branch 16 taken
                       48: branch 18 taken
                     5703: branch 19 taken
      41             6880:       || !isalpha(ch);
      42                 : }
      43                 : 
      44             1177: static const char* parseWord(const char* s) {
      45             1177:   char ch = *s, prev = '\0';
                        0: branch 0 not taken
                     1177: branch 1 taken
      46             1177:   assert(ch != '\0');
      47             1177:   char next = *(s+1);
                     5703: branch 1 taken
                     1177: branch 2 taken
      48             8057:   while (!isWordEnd(ch, prev, next)) {
      49             5703:     prev = ch;
      50             5703:     ch = next;
      51             5703:     next = *((++s)+1);
      52                 :   }
      53             1177:   return s;
      54                 : }
      55                 : 
      56              454: cocoa::NamingConvention cocoa::deriveNamingConvention(Selector S) {
      57              454:   IdentifierInfo *II = S.getIdentifierInfoForSlot(0);
      58                 : 
                        2: branch 0 taken
                      452: branch 1 taken
      59              454:   if (!II)
      60                2:     return NoConvention;
      61                 : 
      62              452:   const char *s = II->getNameStart();
      63                 : 
      64                 :   // A method/function name may contain a prefix.  We don't know it is there,
      65                 :   // however, until we encounter the first '_'.
      66              452:   bool InPossiblePrefix = true;
      67              452:   bool AtBeginning = true;
      68              452:   NamingConvention C = NoConvention;
      69                 : 
                     1363: branch 0 taken
                      416: branch 1 taken
      70             2231:   while (*s != '\0') {
      71                 :     // Skip '_'.
                       54: branch 0 taken
                     1309: branch 1 taken
      72             1363:     if (*s == '_') {
                       46: branch 0 taken
                        8: branch 1 taken
      73               54:       if (InPossiblePrefix) {
      74                 :         // If we already have a convention, return it.  Otherwise, skip
      75                 :         // the prefix as if it wasn't there.
                       12: branch 0 taken
                       34: branch 1 taken
      76               46:         if (C != NoConvention)
      77               12:           break;
      78                 :         
      79               34:         InPossiblePrefix = false;
      80               34:         AtBeginning = true;
                        0: branch 0 not taken
                       34: branch 1 taken
      81               34:         assert(C == NoConvention);
      82                 :       }
      83               42:       ++s;
      84               42:       continue;
      85                 :     }
      86                 : 
      87                 :     // Skip numbers, ':', etc.
                      132: branch 1 taken
                     1177: branch 2 taken
      88             1309:     if (!isalpha(*s)) {
      89              132:       ++s;
      90              132:       continue;
      91                 :     }
      92                 : 
      93             1177:     const char *wordEnd = parseWord(s);
                        0: branch 0 not taken
                     1177: branch 1 taken
      94             1177:     assert(wordEnd > s);
      95             1177:     unsigned len = wordEnd - s;
      96                 : 
                      572: branch 0 taken
                      154: branch 1 taken
                      338: branch 2 taken
                      113: branch 3 taken
      97             1177:     switch (len) {
      98                 :     default:
      99              572:       break;
     100                 :     case 3:
     101                 :       // Methods starting with 'new' follow the create rule.
                       86: branch 0 taken
                       68: branch 1 taken
                       34: branch 5 taken
                       52: branch 6 taken
                       34: branch 7 taken
                      120: branch 8 taken
     102              154:       if (AtBeginning && StringRef(s, len).equals_lower("new"))
     103               34:         C = CreateRule;
     104              154:       break;
     105                 :     case 4:
     106                 :       // Methods starting with 'alloc' or contain 'copy' follow the
     107                 :       // create rule
                      221: branch 0 taken
                      117: branch 1 taken
                       32: branch 5 taken
                      189: branch 6 taken
                       32: branch 7 taken
                      306: branch 8 taken
     108              338:       if (C == NoConvention && StringRef(s, len).equals_lower("copy"))
     109               32:         C = CreateRule;
     110                 :       else // Methods starting with 'init' follow the init rule.
                      135: branch 0 taken
                      171: branch 1 taken
                       95: branch 5 taken
                       40: branch 6 taken
                       95: branch 7 taken
                      211: branch 8 taken
     111              306:         if (AtBeginning && StringRef(s, len).equals_lower("init"))
     112               95:           C = InitRule;
     113              338:       break;
     114                 :     case 5:
                       52: branch 0 taken
                       61: branch 1 taken
                        0: branch 5 not taken
                       52: branch 6 taken
                        0: branch 7 not taken
                      113: branch 8 taken
     115              113:       if (AtBeginning && StringRef(s, len).equals_lower("alloc"))
     116                0:         C = CreateRule;
     117                 :       break;
     118                 :     }
     119                 : 
     120                 :     // If we aren't in the prefix and have a derived convention then just
     121                 :     // return it now.
                       54: branch 0 taken
                     1123: branch 1 taken
                       24: branch 2 taken
                       30: branch 3 taken
     122             1177:     if (!InPossiblePrefix && C != NoConvention)
     123               24:       return C;
     124                 : 
     125             1153:     AtBeginning = false;
     126             1153:     s = wordEnd;
     127                 :   }
     128                 : 
     129                 :   // We will get here if there wasn't more than one word
     130                 :   // after the prefix.
     131              428:   return C;
     132                 : }
     133                 : 
     134                 : bool cocoa::isRefType(QualType RetTy, llvm::StringRef Prefix,
     135             2103:                       llvm::StringRef Name) {
     136                 :   // Recursively walk the typedef stack, allowing typedefs of reference types.
                      902: branch 2 taken
                     1201: branch 3 taken
     137             2640:   while (TypedefType* TD = dyn_cast<TypedefType>(RetTy.getTypePtr())) {
     138              902:     llvm::StringRef TDName = TD->getDecl()->getIdentifier()->getName();
                      365: branch 1 taken
                      537: branch 2 taken
                      365: branch 5 taken
                        0: branch 6 not taken
                      365: branch 7 taken
                      537: branch 8 taken
     139              902:     if (TDName.startswith(Prefix) && TDName.endswith("Ref"))
     140              365:       return true;
     141                 :     
     142              537:     RetTy = TD->getDecl()->getUnderlyingType();
     143                 :   }
     144                 :   
                      895: branch 1 taken
                      306: branch 2 taken
     145             1201:   if (Name.empty())
     146              895:     return false;
     147                 :   
     148                 :   // Is the type void*?
     149              306:   const PointerType* PT = RetTy->getAs<PointerType>();
                      148: branch 4 taken
                      158: branch 5 taken
     150              306:   if (!(PT->getPointeeType().getUnqualifiedType()->isVoidType()))
     151              148:     return false;
     152                 :   
     153                 :   // Does the name start with the prefix?
     154              158:   return Name.startswith(Prefix);
     155                 : }
     156                 : 
     157              119: bool cocoa::isCFObjectRef(QualType T) {
     158                 :   return isRefType(T, "CF") || // Core Foundation.
     159                 :          isRefType(T, "CG") || // Core Graphics.
     160                 :          isRefType(T, "DADisk") || // Disk Arbitration API.
     161                 :          isRefType(T, "DADissenter") ||
                      101: branch 3 taken
                       18: branch 4 taken
                      101: branch 8 taken
                        0: branch 9 not taken
                      101: branch 13 taken
                        0: branch 14 not taken
                      101: branch 18 taken
                        0: branch 19 not taken
                        0: branch 23 not taken
                      101: branch 24 taken
     162              119:          isRefType(T, "DASessionRef");
     163                 : }
     164                 : 
     165                 : 
     166             1966: bool cocoa::isCocoaObjectRef(QualType Ty) {
                     1440: branch 2 taken
                      526: branch 3 taken
     167             1966:   if (!Ty->isObjCObjectPointerType())
     168             1440:     return false;
     169                 :   
     170              526:   const ObjCObjectPointerType *PT = Ty->getAs<ObjCObjectPointerType>();
     171                 :   
     172                 :   // Can be true for objects with the 'NSObject' attribute.
                        0: branch 0 not taken
                      526: branch 1 taken
     173              526:   if (!PT)
     174                0:     return true;
     175                 :   
     176                 :   // We assume that id<..>, id, and "Class" all represent tracked objects.
                      166: branch 1 taken
                      360: branch 2 taken
                      166: branch 4 taken
                        0: branch 5 not taken
                       12: branch 7 taken
                      154: branch 8 taken
                      372: branch 9 taken
                      154: branch 10 taken
     177              526:   if (PT->isObjCIdType() || PT->isObjCQualifiedIdType() ||
     178                 :       PT->isObjCClassType())
     179              372:     return true;
     180                 :   
     181                 :   // Does the interface subclass NSObject?
     182                 :   // FIXME: We can memoize here if this gets too expensive.
     183              154:   const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();
     184                 :   
     185                 :   // Assume that anything declared with a forward declaration and no
     186                 :   // @interface subclasses NSObject.
                        4: branch 1 taken
                      150: branch 2 taken
     187              154:   if (ID->isForwardDecl())
     188                4:     return true;
     189                 :   
                      286: branch 1 taken
                        2: branch 2 taken
     190              288:   for ( ; ID ; ID = ID->getSuperClass())
                      148: branch 4 taken
                      138: branch 5 taken
     191              286:     if (ID->getIdentifier()->getName() == "NSObject")
     192              148:       return true;
     193                 :   
     194                2:   return false;
     195                 : }

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