1 //===- CocoaConventions.h - Special handling of Cocoa conventions -*- C++ -*--//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file implements cocoa naming convention analysis.
12 //===----------------------------------------------------------------------===//
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;
23 // The "fundamental rule" for naming conventions of methods:
24 // (url broken into two lines)
25 // http://developer.apple.com/documentation/Cocoa/Conceptual/
26 // MemoryMgmt/Tasks/MemoryManagementRules.html
28 // "You take ownership of an object if you create it using a method whose name
29 // begins with "alloc" or "new" or contains "copy" (for example, alloc,
30 // newObject, or mutableCopy), or if you send it a retain message. You are
31 // responsible for relinquishing ownership of objects you own using release
32 // or autorelease. Any other time you receive an object, you must
36 cocoa::NamingConvention cocoa::deriveNamingConvention(Selector S,
37 const ObjCMethodDecl *MD) {
38 switch (MD && MD->hasAttr<ObjCMethodFamilyAttr>()? MD->getMethodFamily()
39 : S.getMethodFamily()) {
48 case OMF_performSelector:
60 llvm_unreachable("unexpected naming convention");
64 bool cocoa::isRefType(QualType RetTy, StringRef Prefix,
66 // Recursively walk the typedef stack, allowing typedefs of reference types.
67 while (const TypedefType *TD = dyn_cast<TypedefType>(RetTy.getTypePtr())) {
68 StringRef TDName = TD->getDecl()->getIdentifier()->getName();
69 if (TDName.startswith(Prefix) && TDName.endswith("Ref"))
72 RetTy = TD->getDecl()->getUnderlyingType();
79 const PointerType* PT = RetTy->getAs<PointerType>();
80 if (!(PT->getPointeeType().getUnqualifiedType()->isVoidType()))
83 // Does the name start with the prefix?
84 return Name.startswith(Prefix);
87 bool coreFoundation::isCFObjectRef(QualType T) {
88 return cocoa::isRefType(T, "CF") || // Core Foundation.
89 cocoa::isRefType(T, "CG") || // Core Graphics.
90 cocoa::isRefType(T, "DADisk") || // Disk Arbitration API.
91 cocoa::isRefType(T, "DADissenter") ||
92 cocoa::isRefType(T, "DASessionRef");
96 bool cocoa::isCocoaObjectRef(QualType Ty) {
97 if (!Ty->isObjCObjectPointerType())
100 const ObjCObjectPointerType *PT = Ty->getAs<ObjCObjectPointerType>();
102 // Can be true for objects with the 'NSObject' attribute.
106 // We assume that id<..>, id, Class, and Class<..> all represent tracked
108 if (PT->isObjCIdType() || PT->isObjCQualifiedIdType() ||
109 PT->isObjCClassType() || PT->isObjCQualifiedClassType())
112 // Does the interface subclass NSObject?
113 // FIXME: We can memoize here if this gets too expensive.
114 const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();
116 // Assume that anything declared with a forward declaration and no
117 // @interface subclasses NSObject.
118 if (ID->isForwardDecl())
121 for ( ; ID ; ID = ID->getSuperClass())
122 if (ID->getIdentifier()->getName() == "NSObject")
128 bool coreFoundation::followsCreateRule(const FunctionDecl *fn) {
129 // For now, *just* base this on the function name, not on anything else.
131 const IdentifierInfo *ident = fn->getIdentifier();
132 if (!ident) return false;
133 StringRef functionName = ident->getName();
135 StringRef::iterator it = functionName.begin();
136 StringRef::iterator start = it;
137 StringRef::iterator endI = functionName.end();
140 // Scan for the start of 'create' or 'copy'.
141 for ( ; it != endI ; ++it) {
142 // Search for the first character. It can either be 'C' or 'c'.
144 if (ch == 'C' || ch == 'c') {
145 // Make sure this isn't something like 'recreate' or 'Scopy'.
146 if (ch == 'c' && it != start && isalpha(*(it - 1)))
154 // Did we hit the end of the string? If so, we didn't find a match.
158 // Scan for *lowercase* 'reate' or 'opy', followed by no lowercase
160 StringRef suffix = functionName.substr(it - start);
161 if (suffix.startswith("reate")) {
164 else if (suffix.startswith("opy")) {
171 if (it == endI || !islower(*it))
174 // If we matched a lowercase character, it isn't the end of the
175 // word. Keep scanning.