1a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek//===- CocoaConventions.h - Special handling of Cocoa conventions -*- C++ -*--// 2a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek// 3a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek// The LLVM Compiler Infrastructure 4a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek// 5a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek// This file is distributed under the University of Illinois Open Source 6a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek// License. See LICENSE.TXT for details. 7a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek// 8a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek//===----------------------------------------------------------------------===// 9a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek// 106970155edde8c79cf22824322470485434b8eb83Francois Pichet// This file implements cocoa naming convention analysis. 11a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek// 12a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek//===----------------------------------------------------------------------===// 13a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek 14bb8fef382ad89b4bc202a1dbd4cd52ced7734479Ted Kremenek#include "clang/Analysis/DomainSpecific/CocoaConventions.h" 1578acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek#include "clang/AST/Type.h" 1678acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek#include "clang/AST/Decl.h" 1778acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek#include "clang/AST/DeclObjC.h" 18a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek#include "llvm/ADT/StringExtras.h" 1985f3d76c0ecfdefcf83ea44a57b7a16119c8a045John McCall#include "llvm/Support/ErrorHandling.h" 20a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenekusing namespace clang; 219ef6537a894c33003359b1f9b9676e9178e028b7Ted Kremenekusing namespace ento; 22a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek 23a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek// The "fundamental rule" for naming conventions of methods: 24a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek// (url broken into two lines) 25a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek// http://developer.apple.com/documentation/Cocoa/Conceptual/ 26a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek// MemoryMgmt/Tasks/MemoryManagementRules.html 27a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek// 28a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek// "You take ownership of an object if you create it using a method whose name 29a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek// begins with "alloc" or "new" or contains "copy" (for example, alloc, 30a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek// newObject, or mutableCopy), or if you send it a retain message. You are 31a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek// responsible for relinquishing ownership of objects you own using release 32a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek// or autorelease. Any other time you receive an object, you must 33a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek// not release it." 34a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek// 35a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek 36786dcd9dca76e3780fdb9642c0db33ed13db1187Douglas Gregorcocoa::NamingConvention cocoa::deriveNamingConvention(Selector S, 37786dcd9dca76e3780fdb9642c0db33ed13db1187Douglas Gregor const ObjCMethodDecl *MD) { 38786dcd9dca76e3780fdb9642c0db33ed13db1187Douglas Gregor switch (MD && MD->hasAttr<ObjCMethodFamilyAttr>()? MD->getMethodFamily() 39786dcd9dca76e3780fdb9642c0db33ed13db1187Douglas Gregor : S.getMethodFamily()) { 4085f3d76c0ecfdefcf83ea44a57b7a16119c8a045John McCall case OMF_None: 4185f3d76c0ecfdefcf83ea44a57b7a16119c8a045John McCall case OMF_autorelease: 4285f3d76c0ecfdefcf83ea44a57b7a16119c8a045John McCall case OMF_dealloc: 4380cb6e69d9e85231588ae604e4bc2bc9a07389afNico Weber case OMF_finalize: 4485f3d76c0ecfdefcf83ea44a57b7a16119c8a045John McCall case OMF_release: 4585f3d76c0ecfdefcf83ea44a57b7a16119c8a045John McCall case OMF_retain: 4685f3d76c0ecfdefcf83ea44a57b7a16119c8a045John McCall case OMF_retainCount: 47926df6cfabf3eaa4afc990c097fa4619b76a9b57Douglas Gregor case OMF_self: 48170579ffc614510815c2fd34112da2970a7e9336Fariborz Jahanian case OMF_performSelector: 495078d46af381b27be1c7e3c3e0c517e4cf7cc064Argyrios Kyrtzidis return NoConvention; 505078d46af381b27be1c7e3c3e0c517e4cf7cc064Argyrios Kyrtzidis 5185f3d76c0ecfdefcf83ea44a57b7a16119c8a045John McCall case OMF_init: 5285f3d76c0ecfdefcf83ea44a57b7a16119c8a045John McCall return InitRule; 53a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek 5485f3d76c0ecfdefcf83ea44a57b7a16119c8a045John McCall case OMF_alloc: 5585f3d76c0ecfdefcf83ea44a57b7a16119c8a045John McCall case OMF_copy: 5685f3d76c0ecfdefcf83ea44a57b7a16119c8a045John McCall case OMF_mutableCopy: 5785f3d76c0ecfdefcf83ea44a57b7a16119c8a045John McCall case OMF_new: 5885f3d76c0ecfdefcf83ea44a57b7a16119c8a045John McCall return CreateRule; 59a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek } 6085f3d76c0ecfdefcf83ea44a57b7a16119c8a045John McCall llvm_unreachable("unexpected naming convention"); 6185f3d76c0ecfdefcf83ea44a57b7a16119c8a045John McCall return NoConvention; 62a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek} 6378acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek 645f9e272e632e951b1efe824cd16acb4d96077930Chris Lattnerbool cocoa::isRefType(QualType RetTy, StringRef Prefix, 655f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner StringRef Name) { 6678acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek // Recursively walk the typedef stack, allowing typedefs of reference types. 67f4c7371fb1d3cebcfb40abad4537bb82515704eaJohn McCall while (const TypedefType *TD = dyn_cast<TypedefType>(RetTy.getTypePtr())) { 685f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner StringRef TDName = TD->getDecl()->getIdentifier()->getName(); 69b6f3c70fb8a0def24bcaa937dc28358f20859c73Benjamin Kramer if (TDName.startswith(Prefix) && TDName.endswith("Ref")) 7078acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek return true; 7178acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek 7278acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek RetTy = TD->getDecl()->getUnderlyingType(); 7378acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek } 7478acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek 75b6f3c70fb8a0def24bcaa937dc28358f20859c73Benjamin Kramer if (Name.empty()) 7678acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek return false; 7778acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek 7878acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek // Is the type void*? 7978acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek const PointerType* PT = RetTy->getAs<PointerType>(); 8078acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek if (!(PT->getPointeeType().getUnqualifiedType()->isVoidType())) 8178acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek return false; 8278acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek 8378acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek // Does the name start with the prefix? 84b6f3c70fb8a0def24bcaa937dc28358f20859c73Benjamin Kramer return Name.startswith(Prefix); 8578acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek} 8678acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek 870556048ae8ff743d0abb9fa88a0d0ee8e9123742Ted Kremenekbool coreFoundation::isCFObjectRef(QualType T) { 880556048ae8ff743d0abb9fa88a0d0ee8e9123742Ted Kremenek return cocoa::isRefType(T, "CF") || // Core Foundation. 890556048ae8ff743d0abb9fa88a0d0ee8e9123742Ted Kremenek cocoa::isRefType(T, "CG") || // Core Graphics. 900556048ae8ff743d0abb9fa88a0d0ee8e9123742Ted Kremenek cocoa::isRefType(T, "DADisk") || // Disk Arbitration API. 910556048ae8ff743d0abb9fa88a0d0ee8e9123742Ted Kremenek cocoa::isRefType(T, "DADissenter") || 920556048ae8ff743d0abb9fa88a0d0ee8e9123742Ted Kremenek cocoa::isRefType(T, "DASessionRef"); 9378acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek} 9478acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek 9578acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek 9678acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenekbool cocoa::isCocoaObjectRef(QualType Ty) { 9778acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek if (!Ty->isObjCObjectPointerType()) 9878acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek return false; 9978acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek 10078acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek const ObjCObjectPointerType *PT = Ty->getAs<ObjCObjectPointerType>(); 10178acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek 10278acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek // Can be true for objects with the 'NSObject' attribute. 10378acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek if (!PT) 10478acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek return true; 10578acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek 1064019c4f692e7b8b2d7a7b6a377c78337596052e4Ted Kremenek // We assume that id<..>, id, Class, and Class<..> all represent tracked 1074019c4f692e7b8b2d7a7b6a377c78337596052e4Ted Kremenek // objects. 10878acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek if (PT->isObjCIdType() || PT->isObjCQualifiedIdType() || 1094019c4f692e7b8b2d7a7b6a377c78337596052e4Ted Kremenek PT->isObjCClassType() || PT->isObjCQualifiedClassType()) 11078acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek return true; 11178acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek 11278acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek // Does the interface subclass NSObject? 11378acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek // FIXME: We can memoize here if this gets too expensive. 11478acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek const ObjCInterfaceDecl *ID = PT->getInterfaceDecl(); 11578acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek 11678acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek // Assume that anything declared with a forward declaration and no 11778acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek // @interface subclasses NSObject. 11878acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek if (ID->isForwardDecl()) 11978acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek return true; 12078acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek 12178acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek for ( ; ID ; ID = ID->getSuperClass()) 12278acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek if (ID->getIdentifier()->getName() == "NSObject") 12378acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek return true; 12478acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek 12578acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek return false; 12678acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek} 1270556048ae8ff743d0abb9fa88a0d0ee8e9123742Ted Kremenek 1287df2ff45f101c87398329d0ea23c1377328dca40John McCallbool coreFoundation::followsCreateRule(const FunctionDecl *fn) { 1297df2ff45f101c87398329d0ea23c1377328dca40John McCall // For now, *just* base this on the function name, not on anything else. 1307df2ff45f101c87398329d0ea23c1377328dca40John McCall 1317df2ff45f101c87398329d0ea23c1377328dca40John McCall const IdentifierInfo *ident = fn->getIdentifier(); 1327df2ff45f101c87398329d0ea23c1377328dca40John McCall if (!ident) return false; 1337df2ff45f101c87398329d0ea23c1377328dca40John McCall StringRef functionName = ident->getName(); 1347df2ff45f101c87398329d0ea23c1377328dca40John McCall 1355f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner StringRef::iterator it = functionName.begin(); 1365f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner StringRef::iterator start = it; 1375f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner StringRef::iterator endI = functionName.end(); 138797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek 139797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek while (true) { 140797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek // Scan for the start of 'create' or 'copy'. 141797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek for ( ; it != endI ; ++it) { 142797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek // Search for the first character. It can either be 'C' or 'c'. 143797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek char ch = *it; 144797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek if (ch == 'C' || ch == 'c') { 1457df2ff45f101c87398329d0ea23c1377328dca40John McCall // Make sure this isn't something like 'recreate' or 'Scopy'. 1467df2ff45f101c87398329d0ea23c1377328dca40John McCall if (ch == 'c' && it != start && isalpha(*(it - 1))) 1477df2ff45f101c87398329d0ea23c1377328dca40John McCall continue; 1487df2ff45f101c87398329d0ea23c1377328dca40John McCall 149797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek ++it; 150797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek break; 151797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek } 152797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek } 153797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek 154797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek // Did we hit the end of the string? If so, we didn't find a match. 155797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek if (it == endI) 156797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek return false; 157797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek 158797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek // Scan for *lowercase* 'reate' or 'opy', followed by no lowercase 159797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek // character. 1605f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner StringRef suffix = functionName.substr(it - start); 161797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek if (suffix.startswith("reate")) { 162797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek it += 5; 163797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek } 164797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek else if (suffix.startswith("opy")) { 165797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek it += 3; 1663060178ad9df29789505c1e6debcfc80a3a13587Chad Rosier } else { 167797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek // Keep scanning. 168797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek continue; 169797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek } 170797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek 171797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek if (it == endI || !islower(*it)) 172797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek return true; 173797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek 174797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek // If we matched a lowercase character, it isn't the end of the 175797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek // word. Keep scanning. 176797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek } 177797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek 178797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek return false; 1790556048ae8ff743d0abb9fa88a0d0ee8e9123742Ted Kremenek} 180