12061Sjkh//===- CocoaConventions.h - Special handling of Cocoa conventions -*- C++ -*--// 250479Speter// 32061Sjkh// The LLVM Compiler Infrastructure 438666Sjb// 532427Sjb// This file is distributed under the University of Illinois Open Source 6111131Sru// License. See LICENSE.TXT for details. 7111131Sru// 838666Sjb//===----------------------------------------------------------------------===// 938666Sjb// 1038666Sjb// This file implements cocoa naming convention analysis. 1138666Sjb// 1264049Salex//===----------------------------------------------------------------------===// 1364049Salex 14116679Ssimokawa#include "clang/Analysis/DomainSpecific/CocoaConventions.h" 1566071Smarkm#include "clang/AST/Decl.h" 16116679Ssimokawa#include "clang/AST/DeclObjC.h" 1773504Sobrien#include "clang/AST/Type.h" 1838666Sjb#include "clang/Basic/CharInfo.h" 19148330Snetchild#include "llvm/ADT/StringExtras.h" 20148330Snetchild#include "llvm/Support/ErrorHandling.h" 21148330Snetchild 2232427Sjbusing namespace clang; 2338666Sjbusing namespace ento; 24108451Sschweikh 2538666Sjbbool cocoa::isRefType(QualType RetTy, StringRef Prefix, 2638666Sjb StringRef Name) { 2738666Sjb // Recursively walk the typedef stack, allowing typedefs of reference types. 2838666Sjb while (const TypedefType *TD = dyn_cast<TypedefType>(RetTy.getTypePtr())) { 2917308Speter StringRef TDName = TD->getDecl()->getIdentifier()->getName(); 3091606Skeramida if (TDName.startswith(Prefix) && TDName.endswith("Ref")) 3119175Sbde return true; 3296205Sjwd // XPC unfortunately uses CF-style function names, but aren't CF types. 3396205Sjwd if (TDName.startswith("xpc_")) 3438042Sbde return false; 3596205Sjwd RetTy = TD->getDecl()->getUnderlyingType(); 3696205Sjwd } 3738042Sbde 3896205Sjwd if (Name.empty()) 3996205Sjwd return false; 4017308Speter 4196205Sjwd // Is the type void*? 4296205Sjwd const PointerType* PT = RetTy->getAs<PointerType>(); 4317308Speter if (!(PT->getPointeeType().getUnqualifiedType()->isVoidType())) 44148330Snetchild return false; 45148330Snetchild 46148330Snetchild // Does the name start with the prefix? 47148330Snetchild return Name.startswith(Prefix); 48148330Snetchild} 49148330Snetchild 50148330Snetchildbool coreFoundation::isCFObjectRef(QualType T) { 51148330Snetchild return cocoa::isRefType(T, "CF") || // Core Foundation. 52148330Snetchild cocoa::isRefType(T, "CG") || // Core Graphics. 53148330Snetchild cocoa::isRefType(T, "DADisk") || // Disk Arbitration API. 54148330Snetchild cocoa::isRefType(T, "DADissenter") || 5596205Sjwd cocoa::isRefType(T, "DASessionRef"); 5696205Sjwd} 5796205Sjwd 5898775Sdillon 5998723Sdillonbool cocoa::isCocoaObjectRef(QualType Ty) { 6098723Sdillon if (!Ty->isObjCObjectPointerType()) 6198723Sdillon return false; 6298723Sdillon 6338666Sjb const ObjCObjectPointerType *PT = Ty->getAs<ObjCObjectPointerType>(); 6438666Sjb 6517308Speter // Can be true for objects with the 'NSObject' attribute. 66123311Speter if (!PT) 67123311Speter return true; 68123311Speter 69123311Speter // We assume that id<..>, id, Class, and Class<..> all represent tracked 70148330Snetchild // objects. 71148330Snetchild if (PT->isObjCIdType() || PT->isObjCQualifiedIdType() || 72148330Snetchild PT->isObjCClassType() || PT->isObjCQualifiedClassType()) 73116679Ssimokawa return true; 74120760Sru 75128189Sdes // Does the interface subclass NSObject? 76127360Sru // FIXME: We can memoize here if this gets too expensive. 77123311Speter const ObjCInterfaceDecl *ID = PT->getInterfaceDecl(); 78137288Speter 79147425Sru // Assume that anything declared with a forward declaration and no 802061Sjkh // @interface subclasses NSObject. 8197769Sru if (!ID->hasDefinition()) 8297252Sru return true; 83119579Sru 8497252Sru for ( ; ID ; ID = ID->getSuperClass()) 8595730Sru if (ID->getIdentifier()->getName() == "NSObject") 8695793Sru return true; 87111617Sru 8895730Sru return false; 89116679Ssimokawa} 9095730Sru 91116679Ssimokawabool coreFoundation::followsCreateRule(const FunctionDecl *fn) { 9295730Sru // For now, *just* base this on the function name, not on anything else. 93110035Sru 94107516Sru const IdentifierInfo *ident = fn->getIdentifier(); 95138921Sru if (!ident) return false; 96138921Sru StringRef functionName = ident->getName(); 97138921Sru 98133942Sru StringRef::iterator it = functionName.begin(); 99133942Sru StringRef::iterator start = it; 100133942Sru StringRef::iterator endI = functionName.end(); 101133942Sru 102110035Sru while (true) { 103117234Sru // Scan for the start of 'create' or 'copy'. 104110035Sru for ( ; it != endI ; ++it) { 105117229Sru // Search for the first character. It can either be 'C' or 'c'. 106117234Sru char ch = *it; 10754324Smarcel if (ch == 'C' || ch == 'c') { 10817308Speter // Make sure this isn't something like 'recreate' or 'Scopy'. 109119519Smarcel if (ch == 'c' && it != start && isLetter(*(it - 1))) 110119519Smarcel continue; 111119519Smarcel 112119519Smarcel ++it; 113119519Smarcel break; 114119519Smarcel } 115119579Sru } 116119519Smarcel 117119519Smarcel // Did we hit the end of the string? If so, we didn't find a match. 118119519Smarcel if (it == endI) 119119519Smarcel return false; 120119519Smarcel 121126031Sgad // Scan for *lowercase* 'reate' or 'opy', followed by no lowercase 122126024Sgad // character. 123126024Sgad StringRef suffix = functionName.substr(it - start); 124126024Sgad if (suffix.startswith("reate")) { 125126024Sgad it += 5; 126126024Sgad } 127126024Sgad else if (suffix.startswith("opy")) { 128126024Sgad it += 3; 129126024Sgad } else { 130126024Sgad // Keep scanning. 131126024Sgad continue; 132126024Sgad } 133126024Sgad 134126024Sgad if (it == endI || !isLowercase(*it)) 135126031Sgad return true; 136126024Sgad 137126024Sgad // If we matched a lowercase character, it isn't the end of the 138126024Sgad // word. Keep scanning. 139126024Sgad } 140126024Sgad} 141126024Sgad