CocoaConventions.cpp revision 5a4f98ff943e6a501b0fe47ade007c9bbf96cb88
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/Analysis/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 20using namespace clang; 21using namespace GR; 22 23using llvm::StringRef; 24 25// The "fundamental rule" for naming conventions of methods: 26// (url broken into two lines) 27// http://developer.apple.com/documentation/Cocoa/Conceptual/ 28// MemoryMgmt/Tasks/MemoryManagementRules.html 29// 30// "You take ownership of an object if you create it using a method whose name 31// begins with "alloc" or "new" or contains "copy" (for example, alloc, 32// newObject, or mutableCopy), or if you send it a retain message. You are 33// responsible for relinquishing ownership of objects you own using release 34// or autorelease. Any other time you receive an object, you must 35// not release it." 36// 37 38static bool isWordEnd(char ch, char prev, char next) { 39 return ch == '\0' 40 || (islower(prev) && isupper(ch)) // xxxC 41 || (isupper(prev) && isupper(ch) && islower(next)) // XXCreate 42 || !isalpha(ch); 43} 44 45static const char* parseWord(const char* s) { 46 char ch = *s, prev = '\0'; 47 assert(ch != '\0'); 48 char next = *(s+1); 49 while (!isWordEnd(ch, prev, next)) { 50 prev = ch; 51 ch = next; 52 next = *((++s)+1); 53 } 54 return s; 55} 56 57cocoa::NamingConvention cocoa::deriveNamingConvention(Selector S) { 58 IdentifierInfo *II = S.getIdentifierInfoForSlot(0); 59 60 if (!II) 61 return NoConvention; 62 63 const char *s = II->getNameStart(); 64 65 // A method/function name may contain a prefix. We don't know it is there, 66 // however, until we encounter the first '_'. 67 while (*s != '\0') { 68 // Skip '_', numbers, ':', etc. 69 if (*s == '_' || !isalpha(*s)) { 70 ++s; 71 continue; 72 } 73 break; 74 } 75 76 // Parse the first word, and look for specific keywords. 77 const char *wordEnd = parseWord(s); 78 assert(wordEnd > s); 79 unsigned len = wordEnd - s; 80 81 switch (len) { 82 default: 83 return NoConvention; 84 case 3: 85 // Methods starting with 'new' follow the create rule. 86 return (memcmp(s, "new", 3) == 0) ? CreateRule : NoConvention; 87 case 4: 88 // Methods starting with 'copy' follow the create rule. 89 if (memcmp(s, "copy", 4) == 0) 90 return CreateRule; 91 // Methods starting with 'init' follow the init rule. 92 if (memcmp(s, "init", 4) == 0) 93 return InitRule; 94 return NoConvention; 95 case 5: 96 return (memcmp(s, "alloc", 5) == 0) ? CreateRule : NoConvention; 97 case 7: 98 // Methods starting with 'mutableCopy' follow the create rule. 99 if (memcmp(s, "mutable", 7) == 0) { 100 // Look at the next word to see if it is "Copy". 101 s = wordEnd; 102 if (*s != '\0') { 103 wordEnd = parseWord(s); 104 len = wordEnd - s; 105 if (len == 4 && memcmp(s, "Copy", 4) == 0) 106 return CreateRule; 107 } 108 } 109 return NoConvention; 110 } 111} 112 113bool cocoa::isRefType(QualType RetTy, llvm::StringRef Prefix, 114 llvm::StringRef Name) { 115 // Recursively walk the typedef stack, allowing typedefs of reference types. 116 while (TypedefType* TD = dyn_cast<TypedefType>(RetTy.getTypePtr())) { 117 llvm::StringRef TDName = TD->getDecl()->getIdentifier()->getName(); 118 if (TDName.startswith(Prefix) && TDName.endswith("Ref")) 119 return true; 120 121 RetTy = TD->getDecl()->getUnderlyingType(); 122 } 123 124 if (Name.empty()) 125 return false; 126 127 // Is the type void*? 128 const PointerType* PT = RetTy->getAs<PointerType>(); 129 if (!(PT->getPointeeType().getUnqualifiedType()->isVoidType())) 130 return false; 131 132 // Does the name start with the prefix? 133 return Name.startswith(Prefix); 134} 135 136bool cocoa::isCFObjectRef(QualType T) { 137 return isRefType(T, "CF") || // Core Foundation. 138 isRefType(T, "CG") || // Core Graphics. 139 isRefType(T, "DADisk") || // Disk Arbitration API. 140 isRefType(T, "DADissenter") || 141 isRefType(T, "DASessionRef"); 142} 143 144 145bool cocoa::isCocoaObjectRef(QualType Ty) { 146 if (!Ty->isObjCObjectPointerType()) 147 return false; 148 149 const ObjCObjectPointerType *PT = Ty->getAs<ObjCObjectPointerType>(); 150 151 // Can be true for objects with the 'NSObject' attribute. 152 if (!PT) 153 return true; 154 155 // We assume that id<..>, id, Class, and Class<..> all represent tracked 156 // objects. 157 if (PT->isObjCIdType() || PT->isObjCQualifiedIdType() || 158 PT->isObjCClassType() || PT->isObjCQualifiedClassType()) 159 return true; 160 161 // Does the interface subclass NSObject? 162 // FIXME: We can memoize here if this gets too expensive. 163 const ObjCInterfaceDecl *ID = PT->getInterfaceDecl(); 164 165 // Assume that anything declared with a forward declaration and no 166 // @interface subclasses NSObject. 167 if (ID->isForwardDecl()) 168 return true; 169 170 for ( ; ID ; ID = ID->getSuperClass()) 171 if (ID->getIdentifier()->getName() == "NSObject") 172 return true; 173 174 return false; 175} 176