blob: 7e9e38fd1eaecbd7c29f812e6dc5a07b25769add [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//
Francois Pichet69701552011-06-16 23:19:36 +000010// This file implements cocoa naming convention analysis.
Ted Kremeneka64e89b2010-01-27 06:13:48 +000011//
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"
John McCall85f3d762011-03-02 01:50:55 +000019#include "llvm/Support/ErrorHandling.h"
Ted Kremeneka64e89b2010-01-27 06:13:48 +000020using namespace clang;
Ted Kremenek9ef65372010-12-23 07:20:52 +000021using namespace ento;
Ted Kremeneka64e89b2010-01-27 06:13:48 +000022
Chris Lattner5f9e2722011-07-23 10:55:15 +000023bool cocoa::isRefType(QualType RetTy, StringRef Prefix,
24 StringRef Name) {
Ted Kremenek78acdbf2010-01-27 18:00:17 +000025 // Recursively walk the typedef stack, allowing typedefs of reference types.
John McCallf4c73712011-01-19 06:33:43 +000026 while (const TypedefType *TD = dyn_cast<TypedefType>(RetTy.getTypePtr())) {
Chris Lattner5f9e2722011-07-23 10:55:15 +000027 StringRef TDName = TD->getDecl()->getIdentifier()->getName();
Benjamin Kramerb6f3c702010-02-08 18:38:55 +000028 if (TDName.startswith(Prefix) && TDName.endswith("Ref"))
Ted Kremenek78acdbf2010-01-27 18:00:17 +000029 return true;
Ted Kremenek1c879802012-01-04 00:35:48 +000030 // XPC unfortunately uses CF-style function names, but aren't CF types.
31 if (TDName.startswith("xpc_"))
32 return false;
Ted Kremenek78acdbf2010-01-27 18:00:17 +000033 RetTy = TD->getDecl()->getUnderlyingType();
34 }
35
Benjamin Kramerb6f3c702010-02-08 18:38:55 +000036 if (Name.empty())
Ted Kremenek78acdbf2010-01-27 18:00:17 +000037 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?
Benjamin Kramerb6f3c702010-02-08 18:38:55 +000045 return Name.startswith(Prefix);
Ted Kremenek78acdbf2010-01-27 18:00:17 +000046}
47
Ted Kremenek05560482011-07-16 19:50:32 +000048bool 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");
Ted Kremenek78acdbf2010-01-27 18:00:17 +000054}
55
56
57bool 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
Ted Kremenek4019c4f2010-08-05 00:19:24 +000067 // We assume that id<..>, id, Class, and Class<..> all represent tracked
68 // objects.
Ted Kremenek78acdbf2010-01-27 18:00:17 +000069 if (PT->isObjCIdType() || PT->isObjCQualifiedIdType() ||
Ted Kremenek4019c4f2010-08-05 00:19:24 +000070 PT->isObjCClassType() || PT->isObjCQualifiedClassType())
Ted Kremenek78acdbf2010-01-27 18:00:17 +000071 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.
Douglas Gregor7723fec2011-12-15 20:29:51 +000079 if (!ID->hasDefinition())
Ted Kremenek78acdbf2010-01-27 18:00:17 +000080 return true;
81
82 for ( ; ID ; ID = ID->getSuperClass())
83 if (ID->getIdentifier()->getName() == "NSObject")
84 return true;
85
86 return false;
87}
Ted Kremenek05560482011-07-16 19:50:32 +000088
John McCall7df2ff42011-10-01 00:48:56 +000089bool 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
Chris Lattner5f9e2722011-07-23 10:55:15 +000096 StringRef::iterator it = functionName.begin();
97 StringRef::iterator start = it;
98 StringRef::iterator endI = functionName.end();
Ted Kremenek797a7be2011-07-16 19:50:36 +000099
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') {
John McCall7df2ff42011-10-01 00:48:56 +0000106 // Make sure this isn't something like 'recreate' or 'Scopy'.
107 if (ch == 'c' && it != start && isalpha(*(it - 1)))
108 continue;
109
Ted Kremenek797a7be2011-07-16 19:50:36 +0000110 ++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.
Chris Lattner5f9e2722011-07-23 10:55:15 +0000121 StringRef suffix = functionName.substr(it - start);
Ted Kremenek797a7be2011-07-16 19:50:36 +0000122 if (suffix.startswith("reate")) {
123 it += 5;
124 }
125 else if (suffix.startswith("opy")) {
126 it += 3;
Chad Rosier30601782011-08-17 23:08:45 +0000127 } else {
Ted Kremenek797a7be2011-07-16 19:50:36 +0000128 // 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 }
Ted Kremenek05560482011-07-16 19:50:32 +0000138}