12061Sjkh//===- CocoaConventions.h - Special handling of Cocoa conventions -*- C++ -*--//
250479Speter//
32061Sjkh//                     The LLVM Compiler Infrastructure
438666Sjb//
532427Sjb// This file is distributed under the University of Illinois Open Source
6111131Sru// License. See LICENSE.TXT for details.
7111131Sru//
838666Sjb//===----------------------------------------------------------------------===//
938666Sjb//
1038666Sjb// This file implements cocoa naming convention analysis.
1138666Sjb//
1264049Salex//===----------------------------------------------------------------------===//
1364049Salex
14116679Ssimokawa#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
1566071Smarkm#include "clang/AST/Decl.h"
16116679Ssimokawa#include "clang/AST/DeclObjC.h"
1773504Sobrien#include "clang/AST/Type.h"
1838666Sjb#include "clang/Basic/CharInfo.h"
19148330Snetchild#include "llvm/ADT/StringExtras.h"
20148330Snetchild#include "llvm/Support/ErrorHandling.h"
21148330Snetchild
2232427Sjbusing namespace clang;
2338666Sjbusing namespace ento;
24108451Sschweikh
2538666Sjbbool cocoa::isRefType(QualType RetTy, StringRef Prefix,
2638666Sjb                      StringRef Name) {
2738666Sjb  // Recursively walk the typedef stack, allowing typedefs of reference types.
2838666Sjb  while (const TypedefType *TD = dyn_cast<TypedefType>(RetTy.getTypePtr())) {
2917308Speter    StringRef TDName = TD->getDecl()->getIdentifier()->getName();
3091606Skeramida    if (TDName.startswith(Prefix) && TDName.endswith("Ref"))
3119175Sbde      return true;
3296205Sjwd    // XPC unfortunately uses CF-style function names, but aren't CF types.
3396205Sjwd    if (TDName.startswith("xpc_"))
3438042Sbde      return false;
3596205Sjwd    RetTy = TD->getDecl()->getUnderlyingType();
3696205Sjwd  }
3738042Sbde
3896205Sjwd  if (Name.empty())
3996205Sjwd    return false;
4017308Speter
4196205Sjwd  // Is the type void*?
4296205Sjwd  const PointerType* PT = RetTy->getAs<PointerType>();
4317308Speter  if (!(PT->getPointeeType().getUnqualifiedType()->isVoidType()))
44148330Snetchild    return false;
45148330Snetchild
46148330Snetchild  // Does the name start with the prefix?
47148330Snetchild  return Name.startswith(Prefix);
48148330Snetchild}
49148330Snetchild
50148330Snetchildbool coreFoundation::isCFObjectRef(QualType T) {
51148330Snetchild  return cocoa::isRefType(T, "CF") || // Core Foundation.
52148330Snetchild         cocoa::isRefType(T, "CG") || // Core Graphics.
53148330Snetchild         cocoa::isRefType(T, "DADisk") || // Disk Arbitration API.
54148330Snetchild         cocoa::isRefType(T, "DADissenter") ||
5596205Sjwd         cocoa::isRefType(T, "DASessionRef");
5696205Sjwd}
5796205Sjwd
5898775Sdillon
5998723Sdillonbool cocoa::isCocoaObjectRef(QualType Ty) {
6098723Sdillon  if (!Ty->isObjCObjectPointerType())
6198723Sdillon    return false;
6298723Sdillon
6338666Sjb  const ObjCObjectPointerType *PT = Ty->getAs<ObjCObjectPointerType>();
6438666Sjb
6517308Speter  // Can be true for objects with the 'NSObject' attribute.
66123311Speter  if (!PT)
67123311Speter    return true;
68123311Speter
69123311Speter  // We assume that id<..>, id, Class, and Class<..> all represent tracked
70148330Snetchild  // objects.
71148330Snetchild  if (PT->isObjCIdType() || PT->isObjCQualifiedIdType() ||
72148330Snetchild      PT->isObjCClassType() || PT->isObjCQualifiedClassType())
73116679Ssimokawa    return true;
74120760Sru
75128189Sdes  // Does the interface subclass NSObject?
76127360Sru  // FIXME: We can memoize here if this gets too expensive.
77123311Speter  const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();
78137288Speter
79147425Sru  // Assume that anything declared with a forward declaration and no
802061Sjkh  // @interface subclasses NSObject.
8197769Sru  if (!ID->hasDefinition())
8297252Sru    return true;
83119579Sru
8497252Sru  for ( ; ID ; ID = ID->getSuperClass())
8595730Sru    if (ID->getIdentifier()->getName() == "NSObject")
8695793Sru      return true;
87111617Sru
8895730Sru  return false;
89116679Ssimokawa}
9095730Sru
91116679Ssimokawabool coreFoundation::followsCreateRule(const FunctionDecl *fn) {
9295730Sru  // For now, *just* base this on the function name, not on anything else.
93110035Sru
94107516Sru  const IdentifierInfo *ident = fn->getIdentifier();
95138921Sru  if (!ident) return false;
96138921Sru  StringRef functionName = ident->getName();
97138921Sru
98133942Sru  StringRef::iterator it = functionName.begin();
99133942Sru  StringRef::iterator start = it;
100133942Sru  StringRef::iterator endI = functionName.end();
101133942Sru
102110035Sru  while (true) {
103117234Sru    // Scan for the start of 'create' or 'copy'.
104110035Sru    for ( ; it != endI ; ++it) {
105117229Sru      // Search for the first character.  It can either be 'C' or 'c'.
106117234Sru      char ch = *it;
10754324Smarcel      if (ch == 'C' || ch == 'c') {
10817308Speter        // Make sure this isn't something like 'recreate' or 'Scopy'.
109119519Smarcel        if (ch == 'c' && it != start && isLetter(*(it - 1)))
110119519Smarcel          continue;
111119519Smarcel
112119519Smarcel        ++it;
113119519Smarcel        break;
114119519Smarcel      }
115119579Sru    }
116119519Smarcel
117119519Smarcel    // Did we hit the end of the string?  If so, we didn't find a match.
118119519Smarcel    if (it == endI)
119119519Smarcel      return false;
120119519Smarcel
121126031Sgad    // Scan for *lowercase* 'reate' or 'opy', followed by no lowercase
122126024Sgad    // character.
123126024Sgad    StringRef suffix = functionName.substr(it - start);
124126024Sgad    if (suffix.startswith("reate")) {
125126024Sgad      it += 5;
126126024Sgad    }
127126024Sgad    else if (suffix.startswith("opy")) {
128126024Sgad      it += 3;
129126024Sgad    } else {
130126024Sgad      // Keep scanning.
131126024Sgad      continue;
132126024Sgad    }
133126024Sgad
134126024Sgad    if (it == endI || !isLowercase(*it))
135126031Sgad      return true;
136126024Sgad
137126024Sgad    // If we matched a lowercase character, it isn't the end of the
138126024Sgad    // word.  Keep scanning.
139126024Sgad  }
140126024Sgad}
141126024Sgad