1a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek//===- CocoaConventions.h - Special handling of Cocoa conventions -*- C++ -*--//
2a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek//
3a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek//                     The LLVM Compiler Infrastructure
4a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek//
5a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek// This file is distributed under the University of Illinois Open Source
6a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek// License. See LICENSE.TXT for details.
7a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek//
8a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek//===----------------------------------------------------------------------===//
9a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek//
106970155edde8c79cf22824322470485434b8eb83Francois Pichet// This file implements cocoa naming convention analysis.
11a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek//
12a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek//===----------------------------------------------------------------------===//
13a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek
14bb8fef382ad89b4bc202a1dbd4cd52ced7734479Ted Kremenek#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
1578acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek#include "clang/AST/Type.h"
1678acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek#include "clang/AST/Decl.h"
1778acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek#include "clang/AST/DeclObjC.h"
18a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek#include "llvm/ADT/StringExtras.h"
1985f3d76c0ecfdefcf83ea44a57b7a16119c8a045John McCall#include "llvm/Support/ErrorHandling.h"
20a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenekusing namespace clang;
219ef6537a894c33003359b1f9b9676e9178e028b7Ted Kremenekusing namespace ento;
22a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek
23a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek// The "fundamental rule" for naming conventions of methods:
24a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek//  (url broken into two lines)
25a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek//  http://developer.apple.com/documentation/Cocoa/Conceptual/
26a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek//     MemoryMgmt/Tasks/MemoryManagementRules.html
27a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek//
28a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek// "You take ownership of an object if you create it using a method whose name
29a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek//  begins with "alloc" or "new" or contains "copy" (for example, alloc,
30a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek//  newObject, or mutableCopy), or if you send it a retain message. You are
31a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek//  responsible for relinquishing ownership of objects you own using release
32a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek//  or autorelease. Any other time you receive an object, you must
33a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek//  not release it."
34a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek//
35a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek
36786dcd9dca76e3780fdb9642c0db33ed13db1187Douglas Gregorcocoa::NamingConvention cocoa::deriveNamingConvention(Selector S,
37786dcd9dca76e3780fdb9642c0db33ed13db1187Douglas Gregor                                                    const ObjCMethodDecl *MD) {
38786dcd9dca76e3780fdb9642c0db33ed13db1187Douglas Gregor  switch (MD && MD->hasAttr<ObjCMethodFamilyAttr>()? MD->getMethodFamily()
39786dcd9dca76e3780fdb9642c0db33ed13db1187Douglas Gregor                                                   : S.getMethodFamily()) {
4085f3d76c0ecfdefcf83ea44a57b7a16119c8a045John McCall  case OMF_None:
4185f3d76c0ecfdefcf83ea44a57b7a16119c8a045John McCall  case OMF_autorelease:
4285f3d76c0ecfdefcf83ea44a57b7a16119c8a045John McCall  case OMF_dealloc:
4380cb6e69d9e85231588ae604e4bc2bc9a07389afNico Weber  case OMF_finalize:
4485f3d76c0ecfdefcf83ea44a57b7a16119c8a045John McCall  case OMF_release:
4585f3d76c0ecfdefcf83ea44a57b7a16119c8a045John McCall  case OMF_retain:
4685f3d76c0ecfdefcf83ea44a57b7a16119c8a045John McCall  case OMF_retainCount:
47926df6cfabf3eaa4afc990c097fa4619b76a9b57Douglas Gregor  case OMF_self:
48170579ffc614510815c2fd34112da2970a7e9336Fariborz Jahanian  case OMF_performSelector:
495078d46af381b27be1c7e3c3e0c517e4cf7cc064Argyrios Kyrtzidis    return NoConvention;
505078d46af381b27be1c7e3c3e0c517e4cf7cc064Argyrios Kyrtzidis
5185f3d76c0ecfdefcf83ea44a57b7a16119c8a045John McCall  case OMF_init:
5285f3d76c0ecfdefcf83ea44a57b7a16119c8a045John McCall    return InitRule;
53a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek
5485f3d76c0ecfdefcf83ea44a57b7a16119c8a045John McCall  case OMF_alloc:
5585f3d76c0ecfdefcf83ea44a57b7a16119c8a045John McCall  case OMF_copy:
5685f3d76c0ecfdefcf83ea44a57b7a16119c8a045John McCall  case OMF_mutableCopy:
5785f3d76c0ecfdefcf83ea44a57b7a16119c8a045John McCall  case OMF_new:
5885f3d76c0ecfdefcf83ea44a57b7a16119c8a045John McCall    return CreateRule;
59a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek  }
6085f3d76c0ecfdefcf83ea44a57b7a16119c8a045John McCall  llvm_unreachable("unexpected naming convention");
6185f3d76c0ecfdefcf83ea44a57b7a16119c8a045John McCall  return NoConvention;
62a64e89bbfa756816d1e4a48e5d6c03edf1d7f23bTed Kremenek}
6378acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek
645f9e272e632e951b1efe824cd16acb4d96077930Chris Lattnerbool cocoa::isRefType(QualType RetTy, StringRef Prefix,
655f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner                      StringRef Name) {
6678acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek  // Recursively walk the typedef stack, allowing typedefs of reference types.
67f4c7371fb1d3cebcfb40abad4537bb82515704eaJohn McCall  while (const TypedefType *TD = dyn_cast<TypedefType>(RetTy.getTypePtr())) {
685f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner    StringRef TDName = TD->getDecl()->getIdentifier()->getName();
69b6f3c70fb8a0def24bcaa937dc28358f20859c73Benjamin Kramer    if (TDName.startswith(Prefix) && TDName.endswith("Ref"))
7078acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek      return true;
7178acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek
7278acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek    RetTy = TD->getDecl()->getUnderlyingType();
7378acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek  }
7478acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek
75b6f3c70fb8a0def24bcaa937dc28358f20859c73Benjamin Kramer  if (Name.empty())
7678acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek    return false;
7778acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek
7878acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek  // Is the type void*?
7978acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek  const PointerType* PT = RetTy->getAs<PointerType>();
8078acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek  if (!(PT->getPointeeType().getUnqualifiedType()->isVoidType()))
8178acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek    return false;
8278acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek
8378acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek  // Does the name start with the prefix?
84b6f3c70fb8a0def24bcaa937dc28358f20859c73Benjamin Kramer  return Name.startswith(Prefix);
8578acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek}
8678acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek
870556048ae8ff743d0abb9fa88a0d0ee8e9123742Ted Kremenekbool coreFoundation::isCFObjectRef(QualType T) {
880556048ae8ff743d0abb9fa88a0d0ee8e9123742Ted Kremenek  return cocoa::isRefType(T, "CF") || // Core Foundation.
890556048ae8ff743d0abb9fa88a0d0ee8e9123742Ted Kremenek         cocoa::isRefType(T, "CG") || // Core Graphics.
900556048ae8ff743d0abb9fa88a0d0ee8e9123742Ted Kremenek         cocoa::isRefType(T, "DADisk") || // Disk Arbitration API.
910556048ae8ff743d0abb9fa88a0d0ee8e9123742Ted Kremenek         cocoa::isRefType(T, "DADissenter") ||
920556048ae8ff743d0abb9fa88a0d0ee8e9123742Ted Kremenek         cocoa::isRefType(T, "DASessionRef");
9378acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek}
9478acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek
9578acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek
9678acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenekbool cocoa::isCocoaObjectRef(QualType Ty) {
9778acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek  if (!Ty->isObjCObjectPointerType())
9878acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek    return false;
9978acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek
10078acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek  const ObjCObjectPointerType *PT = Ty->getAs<ObjCObjectPointerType>();
10178acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek
10278acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek  // Can be true for objects with the 'NSObject' attribute.
10378acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek  if (!PT)
10478acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek    return true;
10578acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek
1064019c4f692e7b8b2d7a7b6a377c78337596052e4Ted Kremenek  // We assume that id<..>, id, Class, and Class<..> all represent tracked
1074019c4f692e7b8b2d7a7b6a377c78337596052e4Ted Kremenek  // objects.
10878acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek  if (PT->isObjCIdType() || PT->isObjCQualifiedIdType() ||
1094019c4f692e7b8b2d7a7b6a377c78337596052e4Ted Kremenek      PT->isObjCClassType() || PT->isObjCQualifiedClassType())
11078acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek    return true;
11178acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek
11278acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek  // Does the interface subclass NSObject?
11378acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek  // FIXME: We can memoize here if this gets too expensive.
11478acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek  const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();
11578acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek
11678acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek  // Assume that anything declared with a forward declaration and no
11778acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek  // @interface subclasses NSObject.
11878acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek  if (ID->isForwardDecl())
11978acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek    return true;
12078acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek
12178acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek  for ( ; ID ; ID = ID->getSuperClass())
12278acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek    if (ID->getIdentifier()->getName() == "NSObject")
12378acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek      return true;
12478acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek
12578acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek  return false;
12678acdbfb522f62b6e8899e078e48fea44fda287dTed Kremenek}
1270556048ae8ff743d0abb9fa88a0d0ee8e9123742Ted Kremenek
1287df2ff45f101c87398329d0ea23c1377328dca40John McCallbool coreFoundation::followsCreateRule(const FunctionDecl *fn) {
1297df2ff45f101c87398329d0ea23c1377328dca40John McCall  // For now, *just* base this on the function name, not on anything else.
1307df2ff45f101c87398329d0ea23c1377328dca40John McCall
1317df2ff45f101c87398329d0ea23c1377328dca40John McCall  const IdentifierInfo *ident = fn->getIdentifier();
1327df2ff45f101c87398329d0ea23c1377328dca40John McCall  if (!ident) return false;
1337df2ff45f101c87398329d0ea23c1377328dca40John McCall  StringRef functionName = ident->getName();
1347df2ff45f101c87398329d0ea23c1377328dca40John McCall
1355f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner  StringRef::iterator it = functionName.begin();
1365f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner  StringRef::iterator start = it;
1375f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner  StringRef::iterator endI = functionName.end();
138797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek
139797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek  while (true) {
140797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek    // Scan for the start of 'create' or 'copy'.
141797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek    for ( ; it != endI ; ++it) {
142797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek      // Search for the first character.  It can either be 'C' or 'c'.
143797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek      char ch = *it;
144797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek      if (ch == 'C' || ch == 'c') {
1457df2ff45f101c87398329d0ea23c1377328dca40John McCall        // Make sure this isn't something like 'recreate' or 'Scopy'.
1467df2ff45f101c87398329d0ea23c1377328dca40John McCall        if (ch == 'c' && it != start && isalpha(*(it - 1)))
1477df2ff45f101c87398329d0ea23c1377328dca40John McCall          continue;
1487df2ff45f101c87398329d0ea23c1377328dca40John McCall
149797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek        ++it;
150797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek        break;
151797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek      }
152797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek    }
153797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek
154797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek    // Did we hit the end of the string?  If so, we didn't find a match.
155797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek    if (it == endI)
156797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek      return false;
157797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek
158797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek    // Scan for *lowercase* 'reate' or 'opy', followed by no lowercase
159797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek    // character.
1605f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner    StringRef suffix = functionName.substr(it - start);
161797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek    if (suffix.startswith("reate")) {
162797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek      it += 5;
163797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek    }
164797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek    else if (suffix.startswith("opy")) {
165797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek      it += 3;
1663060178ad9df29789505c1e6debcfc80a3a13587Chad Rosier    } else {
167797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek      // Keep scanning.
168797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek      continue;
169797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek    }
170797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek
171797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek    if (it == endI || !islower(*it))
172797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek      return true;
173797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek
174797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek    // If we matched a lowercase character, it isn't the end of the
175797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek    // word.  Keep scanning.
176797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek  }
177797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek
178797a7be0de6fbedaa85082b07ec9ce0674f30773Ted Kremenek  return false;
1790556048ae8ff743d0abb9fa88a0d0ee8e9123742Ted Kremenek}
180