CocoaConventions.cpp revision 5078d46af381b27be1c7e3c3e0c517e4cf7cc064
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 ento; 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 bool ignorePrefix) { 59 IdentifierInfo *II = S.getIdentifierInfoForSlot(0); 60 61 if (!II) 62 return NoConvention; 63 64 const char *s = II->getNameStart(); 65 66 const char *orig = s; 67 // A method/function name may contain a prefix. We don't know it is there, 68 // however, until we encounter the first '_'. 69 while (*s != '\0') { 70 // Skip '_', numbers, ':', etc. 71 if (*s == '_' || !isalpha(*s)) { 72 ++s; 73 continue; 74 } 75 break; 76 } 77 78 if (!ignorePrefix && s != orig) 79 return NoConvention; 80 81 // Parse the first word, and look for specific keywords. 82 const char *wordEnd = parseWord(s); 83 assert(wordEnd > s); 84 unsigned len = wordEnd - s; 85 86 switch (len) { 87 default: 88 return NoConvention; 89 case 3: 90 // Methods starting with 'new' follow the create rule. 91 return (memcmp(s, "new", 3) == 0) ? CreateRule : NoConvention; 92 case 4: 93 // Methods starting with 'copy' follow the create rule. 94 if (memcmp(s, "copy", 4) == 0) 95 return CreateRule; 96 // Methods starting with 'init' follow the init rule. 97 if (memcmp(s, "init", 4) == 0) 98 return InitRule; 99 return NoConvention; 100 case 5: 101 return (memcmp(s, "alloc", 5) == 0) ? CreateRule : NoConvention; 102 case 7: 103 // Methods starting with 'mutableCopy' follow the create rule. 104 if (memcmp(s, "mutable", 7) == 0) { 105 // Look at the next word to see if it is "Copy". 106 s = wordEnd; 107 if (*s != '\0') { 108 wordEnd = parseWord(s); 109 len = wordEnd - s; 110 if (len == 4 && memcmp(s, "Copy", 4) == 0) 111 return CreateRule; 112 } 113 } 114 return NoConvention; 115 } 116} 117 118bool cocoa::isRefType(QualType RetTy, llvm::StringRef Prefix, 119 llvm::StringRef Name) { 120 // Recursively walk the typedef stack, allowing typedefs of reference types. 121 while (TypedefType* TD = dyn_cast<TypedefType>(RetTy.getTypePtr())) { 122 llvm::StringRef TDName = TD->getDecl()->getIdentifier()->getName(); 123 if (TDName.startswith(Prefix) && TDName.endswith("Ref")) 124 return true; 125 126 RetTy = TD->getDecl()->getUnderlyingType(); 127 } 128 129 if (Name.empty()) 130 return false; 131 132 // Is the type void*? 133 const PointerType* PT = RetTy->getAs<PointerType>(); 134 if (!(PT->getPointeeType().getUnqualifiedType()->isVoidType())) 135 return false; 136 137 // Does the name start with the prefix? 138 return Name.startswith(Prefix); 139} 140 141bool cocoa::isCFObjectRef(QualType T) { 142 return isRefType(T, "CF") || // Core Foundation. 143 isRefType(T, "CG") || // Core Graphics. 144 isRefType(T, "DADisk") || // Disk Arbitration API. 145 isRefType(T, "DADissenter") || 146 isRefType(T, "DASessionRef"); 147} 148 149 150bool cocoa::isCocoaObjectRef(QualType Ty) { 151 if (!Ty->isObjCObjectPointerType()) 152 return false; 153 154 const ObjCObjectPointerType *PT = Ty->getAs<ObjCObjectPointerType>(); 155 156 // Can be true for objects with the 'NSObject' attribute. 157 if (!PT) 158 return true; 159 160 // We assume that id<..>, id, Class, and Class<..> all represent tracked 161 // objects. 162 if (PT->isObjCIdType() || PT->isObjCQualifiedIdType() || 163 PT->isObjCClassType() || PT->isObjCQualifiedClassType()) 164 return true; 165 166 // Does the interface subclass NSObject? 167 // FIXME: We can memoize here if this gets too expensive. 168 const ObjCInterfaceDecl *ID = PT->getInterfaceDecl(); 169 170 // Assume that anything declared with a forward declaration and no 171 // @interface subclasses NSObject. 172 if (ID->isForwardDecl()) 173 return true; 174 175 for ( ; ID ; ID = ID->getSuperClass()) 176 if (ID->getIdentifier()->getName() == "NSObject") 177 return true; 178 179 return false; 180} 181