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 implements cocoa naming convention analysis. 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 #include "llvm/Support/ErrorHandling.h" 20 using namespace clang; 21 using namespace ento; 22 23 bool cocoa::isRefType(QualType RetTy, StringRef Prefix, 24 StringRef Name) { 25 // Recursively walk the typedef stack, allowing typedefs of reference types. 26 while (const TypedefType *TD = dyn_cast<TypedefType>(RetTy.getTypePtr())) { 27 StringRef TDName = TD->getDecl()->getIdentifier()->getName(); 28 if (TDName.startswith(Prefix) && TDName.endswith("Ref")) 29 return true; 30 // XPC unfortunately uses CF-style function names, but aren't CF types. 31 if (TDName.startswith("xpc_")) 32 return false; 33 RetTy = TD->getDecl()->getUnderlyingType(); 34 } 35 36 if (Name.empty()) 37 return false; 38 39 // Is the type void*? 40 const PointerType* PT = RetTy->getAs<PointerType>(); 41 if (!(PT->getPointeeType().getUnqualifiedType()->isVoidType())) 42 return false; 43 44 // Does the name start with the prefix? 45 return Name.startswith(Prefix); 46 } 47 48 bool coreFoundation::isCFObjectRef(QualType T) { 49 return cocoa::isRefType(T, "CF") || // Core Foundation. 50 cocoa::isRefType(T, "CG") || // Core Graphics. 51 cocoa::isRefType(T, "DADisk") || // Disk Arbitration API. 52 cocoa::isRefType(T, "DADissenter") || 53 cocoa::isRefType(T, "DASessionRef"); 54 } 55 56 57 bool cocoa::isCocoaObjectRef(QualType Ty) { 58 if (!Ty->isObjCObjectPointerType()) 59 return false; 60 61 const ObjCObjectPointerType *PT = Ty->getAs<ObjCObjectPointerType>(); 62 63 // Can be true for objects with the 'NSObject' attribute. 64 if (!PT) 65 return true; 66 67 // We assume that id<..>, id, Class, and Class<..> all represent tracked 68 // objects. 69 if (PT->isObjCIdType() || PT->isObjCQualifiedIdType() || 70 PT->isObjCClassType() || PT->isObjCQualifiedClassType()) 71 return true; 72 73 // Does the interface subclass NSObject? 74 // FIXME: We can memoize here if this gets too expensive. 75 const ObjCInterfaceDecl *ID = PT->getInterfaceDecl(); 76 77 // Assume that anything declared with a forward declaration and no 78 // @interface subclasses NSObject. 79 if (!ID->hasDefinition()) 80 return true; 81 82 for ( ; ID ; ID = ID->getSuperClass()) 83 if (ID->getIdentifier()->getName() == "NSObject") 84 return true; 85 86 return false; 87 } 88 89 bool coreFoundation::followsCreateRule(const FunctionDecl *fn) { 90 // For now, *just* base this on the function name, not on anything else. 91 92 const IdentifierInfo *ident = fn->getIdentifier(); 93 if (!ident) return false; 94 StringRef functionName = ident->getName(); 95 96 StringRef::iterator it = functionName.begin(); 97 StringRef::iterator start = it; 98 StringRef::iterator endI = functionName.end(); 99 100 while (true) { 101 // Scan for the start of 'create' or 'copy'. 102 for ( ; it != endI ; ++it) { 103 // Search for the first character. It can either be 'C' or 'c'. 104 char ch = *it; 105 if (ch == 'C' || ch == 'c') { 106 // Make sure this isn't something like 'recreate' or 'Scopy'. 107 if (ch == 'c' && it != start && isalpha(*(it - 1))) 108 continue; 109 110 ++it; 111 break; 112 } 113 } 114 115 // Did we hit the end of the string? If so, we didn't find a match. 116 if (it == endI) 117 return false; 118 119 // Scan for *lowercase* 'reate' or 'opy', followed by no lowercase 120 // character. 121 StringRef suffix = functionName.substr(it - start); 122 if (suffix.startswith("reate")) { 123 it += 5; 124 } 125 else if (suffix.startswith("opy")) { 126 it += 3; 127 } else { 128 // Keep scanning. 129 continue; 130 } 131 132 if (it == endI || !islower(*it)) 133 return true; 134 135 // If we matched a lowercase character, it isn't the end of the 136 // word. Keep scanning. 137 } 138 } 139