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/Decl.h" 1678acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek#include "clang/AST/DeclObjC.h" 1755fc873017f10f6f566b182b70f6fc22aefa3464Chandler Carruth#include "clang/AST/Type.h" 183f6f51e28231f65de9c2dd150a2d757b2162cfa3Jordan Rose#include "clang/Basic/CharInfo.h" 19a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek#include "llvm/ADT/StringExtras.h" 2085f3d76c0ecfdefcf83ea44a57b7a16119c8a045John McCall#include "llvm/Support/ErrorHandling.h" 217094dee95f8c915d27097ac18b47d1ef31fd72edJoerg Sonnenberger 22a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenekusing namespace clang; 239ef6537a894c33003359b1f9b9676e9178e028b7Ted Kremenekusing namespace ento; 24a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek 255f9e272e632e951b1efe824cd16acb4d96077930Chris Lattnerbool cocoa::isRefType(QualType RetTy, StringRef Prefix, 265f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner StringRef Name) { 2778acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek // Recursively walk the typedef stack, allowing typedefs of reference types. 28f4c7371fb1d3cebcfb40abad4537bb82515704eaJohn McCall while (const TypedefType *TD = dyn_cast<TypedefType>(RetTy.getTypePtr())) { 295f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner StringRef TDName = TD->getDecl()->getIdentifier()->getName(); 30b6f3c70fb8a0def24bcaa937dc28358f20859c73Benjamin Kramer if (TDName.startswith(Prefix) && TDName.endswith("Ref")) 3178acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek return true; 321c87980ef18dbf4669c7194d60138ff9747d7ab7Ted Kremenek // XPC unfortunately uses CF-style function names, but aren't CF types. 331c87980ef18dbf4669c7194d60138ff9747d7ab7Ted Kremenek if (TDName.startswith("xpc_")) 341c87980ef18dbf4669c7194d60138ff9747d7ab7Ted Kremenek return false; 3578acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek RetTy = TD->getDecl()->getUnderlyingType(); 3678acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek } 3778acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek 38b6f3c70fb8a0def24bcaa937dc28358f20859c73Benjamin Kramer if (Name.empty()) 3978acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek return false; 4078acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek 4178acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek // Is the type void*? 4278acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek const PointerType* PT = RetTy->getAs<PointerType>(); 4378acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek if (!(PT->getPointeeType().getUnqualifiedType()->isVoidType())) 4478acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek return false; 4578acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek 4678acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek // Does the name start with the prefix? 47b6f3c70fb8a0def24bcaa937dc28358f20859c73Benjamin Kramer return Name.startswith(Prefix); 4878acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek} 4978acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek 500556048ae8ff743d0abb9fa88a0d0ee8e9123742Ted Kremenekbool coreFoundation::isCFObjectRef(QualType T) { 510556048ae8ff743d0abb9fa88a0d0ee8e9123742Ted Kremenek return cocoa::isRefType(T, "CF") || // Core Foundation. 520556048ae8ff743d0abb9fa88a0d0ee8e9123742Ted Kremenek cocoa::isRefType(T, "CG") || // Core Graphics. 530556048ae8ff743d0abb9fa88a0d0ee8e9123742Ted Kremenek cocoa::isRefType(T, "DADisk") || // Disk Arbitration API. 540556048ae8ff743d0abb9fa88a0d0ee8e9123742Ted Kremenek cocoa::isRefType(T, "DADissenter") || 550556048ae8ff743d0abb9fa88a0d0ee8e9123742Ted Kremenek cocoa::isRefType(T, "DASessionRef"); 5678acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek} 5778acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek 5878acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek 5978acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenekbool cocoa::isCocoaObjectRef(QualType Ty) { 6078acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek if (!Ty->isObjCObjectPointerType()) 6178acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek return false; 6278acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek 6378acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek const ObjCObjectPointerType *PT = Ty->getAs<ObjCObjectPointerType>(); 6478acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek 6578acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek // Can be true for objects with the 'NSObject' attribute. 6678acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek if (!PT) 6778acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek return true; 6878acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek 694019c4f692e7b8b2d7a7b6a377c78337596052e4Ted Kremenek // We assume that id<..>, id, Class, and Class<..> all represent tracked 704019c4f692e7b8b2d7a7b6a377c78337596052e4Ted Kremenek // objects. 7178acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek if (PT->isObjCIdType() || PT->isObjCQualifiedIdType() || 724019c4f692e7b8b2d7a7b6a377c78337596052e4Ted Kremenek PT->isObjCClassType() || PT->isObjCQualifiedClassType()) 7378acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek return true; 7478acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek 7578acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek // Does the interface subclass NSObject? 7678acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek // FIXME: We can memoize here if this gets too expensive. 7778acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek const ObjCInterfaceDecl *ID = PT->getInterfaceDecl(); 7878acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek 7978acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek // Assume that anything declared with a forward declaration and no 8078acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek // @interface subclasses NSObject. 817723fec9b45b7258c0eddf4cbfd0d335348f5edcDouglas Gregor if (!ID->hasDefinition()) 8278acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek return true; 8378acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek 8478acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek for ( ; ID ; ID = ID->getSuperClass()) 8578acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek if (ID->getIdentifier()->getName() == "NSObject") 8678acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek return true; 8778acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek 8878acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek return false; 8978acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek} 900556048ae8ff743d0abb9fa88a0d0ee8e9123742Ted Kremenek 917df2ff45f101c87398329d0ea23c1377328dca40John McCallbool coreFoundation::followsCreateRule(const FunctionDecl *fn) { 927df2ff45f101c87398329d0ea23c1377328dca40John McCall // For now, *just* base this on the function name, not on anything else. 937df2ff45f101c87398329d0ea23c1377328dca40John McCall 947df2ff45f101c87398329d0ea23c1377328dca40John McCall const IdentifierInfo *ident = fn->getIdentifier(); 957df2ff45f101c87398329d0ea23c1377328dca40John McCall if (!ident) return false; 967df2ff45f101c87398329d0ea23c1377328dca40John McCall StringRef functionName = ident->getName(); 977df2ff45f101c87398329d0ea23c1377328dca40John McCall 985f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner StringRef::iterator it = functionName.begin(); 995f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner StringRef::iterator start = it; 1005f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner StringRef::iterator endI = functionName.end(); 101797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek 102797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek while (true) { 103797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek // Scan for the start of 'create' or 'copy'. 104797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek for ( ; it != endI ; ++it) { 105797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek // Search for the first character. It can either be 'C' or 'c'. 106797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek char ch = *it; 107797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek if (ch == 'C' || ch == 'c') { 1087df2ff45f101c87398329d0ea23c1377328dca40John McCall // Make sure this isn't something like 'recreate' or 'Scopy'. 1093f6f51e28231f65de9c2dd150a2d757b2162cfa3Jordan Rose if (ch == 'c' && it != start && isLetter(*(it - 1))) 1107df2ff45f101c87398329d0ea23c1377328dca40John McCall continue; 1117df2ff45f101c87398329d0ea23c1377328dca40John McCall 112797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek ++it; 113797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek break; 114797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek } 115797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek } 116797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek 117797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek // Did we hit the end of the string? If so, we didn't find a match. 118797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek if (it == endI) 119797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek return false; 120797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek 121797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek // Scan for *lowercase* 'reate' or 'opy', followed by no lowercase 122797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek // character. 1235f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner StringRef suffix = functionName.substr(it - start); 124797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek if (suffix.startswith("reate")) { 125797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek it += 5; 126797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek } 127797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek else if (suffix.startswith("opy")) { 128797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek it += 3; 1293060178ad9df29789505c1e6debcfc80a3a13587Chad Rosier } else { 130797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek // Keep scanning. 131797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek continue; 132797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek } 133797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek 1343f6f51e28231f65de9c2dd150a2d757b2162cfa3Jordan Rose if (it == endI || !isLowercase(*it)) 135797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek return true; 136797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek 137797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek // If we matched a lowercase character, it isn't the end of the 138797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek // word. Keep scanning. 139797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek } 1400556048ae8ff743d0abb9fa88a0d0ee8e9123742Ted Kremenek} 141