rename test
[clang.git] / lib / Analysis / CocoaConventions.cpp
blob22b6c1aaf02139fecffdcb339b25add62877869f
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 defines
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"
20 using namespace clang;
21 using namespace ento;
23 using llvm::StringRef;
25 // The "fundamental rule" for naming conventions of methods:
26 // (url broken into two lines)
27 // http://developer.apple.com/documentation/Cocoa/Conceptual/
28 // MemoryMgmt/Tasks/MemoryManagementRules.html
30 // "You take ownership of an object if you create it using a method whose name
31 // begins with "alloc" or "new" or contains "copy" (for example, alloc,
32 // newObject, or mutableCopy), or if you send it a retain message. You are
33 // responsible for relinquishing ownership of objects you own using release
34 // or autorelease. Any other time you receive an object, you must
35 // not release it."
38 static bool isWordEnd(char ch, char prev, char next) {
39 return ch == '\0'
40 || (islower(prev) && isupper(ch)) // xxxC
41 || (isupper(prev) && isupper(ch) && islower(next)) // XXCreate
42 || !isalpha(ch);
45 static const char* parseWord(const char* s) {
46 char ch = *s, prev = '\0';
47 assert(ch != '\0');
48 char next = *(s+1);
49 while (!isWordEnd(ch, prev, next)) {
50 prev = ch;
51 ch = next;
52 next = *((++s)+1);
54 return s;
57 cocoa::NamingConvention cocoa::deriveNamingConvention(Selector S,
58 bool ignorePrefix) {
59 IdentifierInfo *II = S.getIdentifierInfoForSlot(0);
61 if (!II)
62 return NoConvention;
64 const char *s = II->getNameStart();
66 const char *orig = s;
67 // A method/function name may contain a prefix. We don't know it is there,
68 // however, until we encounter the first '_'.
69 while (*s != '\0') {
70 // Skip '_', numbers, ':', etc.
71 if (*s == '_' || !isalpha(*s)) {
72 ++s;
73 continue;
75 break;
78 if (!ignorePrefix && s != orig)
79 return NoConvention;
81 // Parse the first word, and look for specific keywords.
82 const char *wordEnd = parseWord(s);
83 assert(wordEnd > s);
84 unsigned len = wordEnd - s;
86 switch (len) {
87 default:
88 return NoConvention;
89 case 3:
90 // Methods starting with 'new' follow the create rule.
91 return (memcmp(s, "new", 3) == 0) ? CreateRule : NoConvention;
92 case 4:
93 // Methods starting with 'copy' follow the create rule.
94 if (memcmp(s, "copy", 4) == 0)
95 return CreateRule;
96 // Methods starting with 'init' follow the init rule.
97 if (memcmp(s, "init", 4) == 0)
98 return InitRule;
99 return NoConvention;
100 case 5:
101 return (memcmp(s, "alloc", 5) == 0) ? CreateRule : NoConvention;
102 case 7:
103 // Methods starting with 'mutableCopy' follow the create rule.
104 if (memcmp(s, "mutable", 7) == 0) {
105 // Look at the next word to see if it is "Copy".
106 s = wordEnd;
107 if (*s != '\0') {
108 wordEnd = parseWord(s);
109 len = wordEnd - s;
110 if (len == 4 && memcmp(s, "Copy", 4) == 0)
111 return CreateRule;
114 return NoConvention;
118 bool cocoa::isRefType(QualType RetTy, llvm::StringRef Prefix,
119 llvm::StringRef Name) {
120 // Recursively walk the typedef stack, allowing typedefs of reference types.
121 while (const TypedefType *TD = dyn_cast<TypedefType>(RetTy.getTypePtr())) {
122 llvm::StringRef TDName = TD->getDecl()->getIdentifier()->getName();
123 if (TDName.startswith(Prefix) && TDName.endswith("Ref"))
124 return true;
126 RetTy = TD->getDecl()->getUnderlyingType();
129 if (Name.empty())
130 return false;
132 // Is the type void*?
133 const PointerType* PT = RetTy->getAs<PointerType>();
134 if (!(PT->getPointeeType().getUnqualifiedType()->isVoidType()))
135 return false;
137 // Does the name start with the prefix?
138 return Name.startswith(Prefix);
141 bool cocoa::isCFObjectRef(QualType T) {
142 return isRefType(T, "CF") || // Core Foundation.
143 isRefType(T, "CG") || // Core Graphics.
144 isRefType(T, "DADisk") || // Disk Arbitration API.
145 isRefType(T, "DADissenter") ||
146 isRefType(T, "DASessionRef");
150 bool cocoa::isCocoaObjectRef(QualType Ty) {
151 if (!Ty->isObjCObjectPointerType())
152 return false;
154 const ObjCObjectPointerType *PT = Ty->getAs<ObjCObjectPointerType>();
156 // Can be true for objects with the 'NSObject' attribute.
157 if (!PT)
158 return true;
160 // We assume that id<..>, id, Class, and Class<..> all represent tracked
161 // objects.
162 if (PT->isObjCIdType() || PT->isObjCQualifiedIdType() ||
163 PT->isObjCClassType() || PT->isObjCQualifiedClassType())
164 return true;
166 // Does the interface subclass NSObject?
167 // FIXME: We can memoize here if this gets too expensive.
168 const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();
170 // Assume that anything declared with a forward declaration and no
171 // @interface subclasses NSObject.
172 if (ID->isForwardDecl())
173 return true;
175 for ( ; ID ; ID = ID->getSuperClass())
176 if (ID->getIdentifier()->getName() == "NSObject")
177 return true;
179 return false;