blob: ad359aad258f04437c5aadcab119d5871126005e [file] [log] [blame]
Ted Kremeneka64e89b2010-01-27 06:13:48 +00001//===- 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 defines
11//
12//===----------------------------------------------------------------------===//
13
Ted Kremenekbb8fef32010-12-17 05:21:58 +000014#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
Ted Kremenek78acdbf2010-01-27 18:00:17 +000015#include "clang/AST/Type.h"
16#include "clang/AST/Decl.h"
17#include "clang/AST/DeclObjC.h"
Ted Kremeneka64e89b2010-01-27 06:13:48 +000018#include "llvm/ADT/StringExtras.h"
19
20using namespace clang;
21
22using llvm::StringRef;
23
24// The "fundamental rule" for naming conventions of methods:
25// (url broken into two lines)
26// http://developer.apple.com/documentation/Cocoa/Conceptual/
27// MemoryMgmt/Tasks/MemoryManagementRules.html
28//
29// "You take ownership of an object if you create it using a method whose name
30// begins with "alloc" or "new" or contains "copy" (for example, alloc,
31// newObject, or mutableCopy), or if you send it a retain message. You are
32// responsible for relinquishing ownership of objects you own using release
33// or autorelease. Any other time you receive an object, you must
34// not release it."
35//
36
37static bool isWordEnd(char ch, char prev, char next) {
38 return ch == '\0'
39 || (islower(prev) && isupper(ch)) // xxxC
40 || (isupper(prev) && isupper(ch) && islower(next)) // XXCreate
41 || !isalpha(ch);
42}
43
44static const char* parseWord(const char* s) {
45 char ch = *s, prev = '\0';
46 assert(ch != '\0');
47 char next = *(s+1);
48 while (!isWordEnd(ch, prev, next)) {
49 prev = ch;
50 ch = next;
51 next = *((++s)+1);
52 }
53 return s;
54}
55
56cocoa::NamingConvention cocoa::deriveNamingConvention(Selector S) {
57 IdentifierInfo *II = S.getIdentifierInfoForSlot(0);
58
59 if (!II)
60 return NoConvention;
61
62 const char *s = II->getNameStart();
63
64 // A method/function name may contain a prefix. We don't know it is there,
65 // however, until we encounter the first '_'.
Ted Kremeneka64e89b2010-01-27 06:13:48 +000066 while (*s != '\0') {
Ted Kremenekaf86b0c2010-12-17 04:44:43 +000067 // Skip '_', numbers, ':', etc.
68 if (*s == '_' || !isalpha(*s)) {
Ted Kremeneka64e89b2010-01-27 06:13:48 +000069 ++s;
70 continue;
71 }
Ted Kremenekaf86b0c2010-12-17 04:44:43 +000072 break;
Ted Kremeneka64e89b2010-01-27 06:13:48 +000073 }
74
Ted Kremenekaf86b0c2010-12-17 04:44:43 +000075 // Parse the first word, and look for specific keywords.
76 const char *wordEnd = parseWord(s);
77 assert(wordEnd > s);
78 unsigned len = wordEnd - s;
79
80 switch (len) {
81 default:
82 return NoConvention;
83 case 3:
84 // Methods starting with 'new' follow the create rule.
85 return (memcmp(s, "new", 3) == 0) ? CreateRule : NoConvention;
86 case 4:
87 // Methods starting with 'copy' follow the create rule.
88 if (memcmp(s, "copy", 4) == 0)
89 return CreateRule;
90 // Methods starting with 'init' follow the init rule.
91 if (memcmp(s, "init", 4) == 0)
92 return InitRule;
93 return NoConvention;
94 case 5:
95 return (memcmp(s, "alloc", 5) == 0) ? CreateRule : NoConvention;
96 case 7:
97 // Methods starting with 'mutableCopy' follow the create rule.
98 if (memcmp(s, "mutable", 7) == 0) {
99 // Look at the next word to see if it is "Copy".
100 s = wordEnd;
Ted Kremenek5eef59e2010-12-17 07:11:57 +0000101 if (*s != '\0') {
102 wordEnd = parseWord(s);
103 len = wordEnd - s;
104 if (len == 4 && memcmp(s, "Copy", 4) == 0)
105 return CreateRule;
106 }
Ted Kremenekaf86b0c2010-12-17 04:44:43 +0000107 }
108 return NoConvention;
109 }
Ted Kremeneka64e89b2010-01-27 06:13:48 +0000110}
Ted Kremenek78acdbf2010-01-27 18:00:17 +0000111
Benjamin Kramerb6f3c702010-02-08 18:38:55 +0000112bool cocoa::isRefType(QualType RetTy, llvm::StringRef Prefix,
113 llvm::StringRef Name) {
Ted Kremenek78acdbf2010-01-27 18:00:17 +0000114 // Recursively walk the typedef stack, allowing typedefs of reference types.
115 while (TypedefType* TD = dyn_cast<TypedefType>(RetTy.getTypePtr())) {
116 llvm::StringRef TDName = TD->getDecl()->getIdentifier()->getName();
Benjamin Kramerb6f3c702010-02-08 18:38:55 +0000117 if (TDName.startswith(Prefix) && TDName.endswith("Ref"))
Ted Kremenek78acdbf2010-01-27 18:00:17 +0000118 return true;
119
120 RetTy = TD->getDecl()->getUnderlyingType();
121 }
122
Benjamin Kramerb6f3c702010-02-08 18:38:55 +0000123 if (Name.empty())
Ted Kremenek78acdbf2010-01-27 18:00:17 +0000124 return false;
125
126 // Is the type void*?
127 const PointerType* PT = RetTy->getAs<PointerType>();
128 if (!(PT->getPointeeType().getUnqualifiedType()->isVoidType()))
129 return false;
130
131 // Does the name start with the prefix?
Benjamin Kramerb6f3c702010-02-08 18:38:55 +0000132 return Name.startswith(Prefix);
Ted Kremenek78acdbf2010-01-27 18:00:17 +0000133}
134
135bool cocoa::isCFObjectRef(QualType T) {
136 return isRefType(T, "CF") || // Core Foundation.
137 isRefType(T, "CG") || // Core Graphics.
138 isRefType(T, "DADisk") || // Disk Arbitration API.
139 isRefType(T, "DADissenter") ||
140 isRefType(T, "DASessionRef");
141}
142
143
144bool cocoa::isCocoaObjectRef(QualType Ty) {
145 if (!Ty->isObjCObjectPointerType())
146 return false;
147
148 const ObjCObjectPointerType *PT = Ty->getAs<ObjCObjectPointerType>();
149
150 // Can be true for objects with the 'NSObject' attribute.
151 if (!PT)
152 return true;
153
Ted Kremenek4019c4f2010-08-05 00:19:24 +0000154 // We assume that id<..>, id, Class, and Class<..> all represent tracked
155 // objects.
Ted Kremenek78acdbf2010-01-27 18:00:17 +0000156 if (PT->isObjCIdType() || PT->isObjCQualifiedIdType() ||
Ted Kremenek4019c4f2010-08-05 00:19:24 +0000157 PT->isObjCClassType() || PT->isObjCQualifiedClassType())
Ted Kremenek78acdbf2010-01-27 18:00:17 +0000158 return true;
159
160 // Does the interface subclass NSObject?
161 // FIXME: We can memoize here if this gets too expensive.
162 const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();
163
164 // Assume that anything declared with a forward declaration and no
165 // @interface subclasses NSObject.
166 if (ID->isForwardDecl())
167 return true;
168
169 for ( ; ID ; ID = ID->getSuperClass())
170 if (ID->getIdentifier()->getName() == "NSObject")
171 return true;
172
173 return false;
174}