clang API Documentation

CocoaConventions.cpp
Go to the documentation of this file.
00001 //===- CocoaConventions.h - Special handling of Cocoa conventions -*- C++ -*--//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 // This file implements cocoa naming convention analysis. 
00011 //
00012 //===----------------------------------------------------------------------===//
00013 
00014 #include "clang/Analysis/DomainSpecific/CocoaConventions.h"
00015 #include "clang/AST/Type.h"
00016 #include "clang/AST/Decl.h"
00017 #include "clang/AST/DeclObjC.h"
00018 #include "llvm/ADT/StringExtras.h"
00019 #include "llvm/Support/ErrorHandling.h"
00020 using namespace clang;
00021 using namespace ento;
00022 
00023 bool cocoa::isRefType(QualType RetTy, StringRef Prefix,
00024                       StringRef Name) {
00025   // Recursively walk the typedef stack, allowing typedefs of reference types.
00026   while (const TypedefType *TD = dyn_cast<TypedefType>(RetTy.getTypePtr())) {
00027     StringRef TDName = TD->getDecl()->getIdentifier()->getName();
00028     if (TDName.startswith(Prefix) && TDName.endswith("Ref"))
00029       return true;
00030     // XPC unfortunately uses CF-style function names, but aren't CF types.
00031     if (TDName.startswith("xpc_"))
00032       return false;
00033     RetTy = TD->getDecl()->getUnderlyingType();
00034   }
00035   
00036   if (Name.empty())
00037     return false;
00038   
00039   // Is the type void*?
00040   const PointerType* PT = RetTy->getAs<PointerType>();
00041   if (!(PT->getPointeeType().getUnqualifiedType()->isVoidType()))
00042     return false;
00043   
00044   // Does the name start with the prefix?
00045   return Name.startswith(Prefix);
00046 }
00047 
00048 bool coreFoundation::isCFObjectRef(QualType T) {
00049   return cocoa::isRefType(T, "CF") || // Core Foundation.
00050          cocoa::isRefType(T, "CG") || // Core Graphics.
00051          cocoa::isRefType(T, "DADisk") || // Disk Arbitration API.
00052          cocoa::isRefType(T, "DADissenter") ||
00053          cocoa::isRefType(T, "DASessionRef");
00054 }
00055 
00056 
00057 bool cocoa::isCocoaObjectRef(QualType Ty) {
00058   if (!Ty->isObjCObjectPointerType())
00059     return false;
00060   
00061   const ObjCObjectPointerType *PT = Ty->getAs<ObjCObjectPointerType>();
00062   
00063   // Can be true for objects with the 'NSObject' attribute.
00064   if (!PT)
00065     return true;
00066   
00067   // We assume that id<..>, id, Class, and Class<..> all represent tracked
00068   // objects.
00069   if (PT->isObjCIdType() || PT->isObjCQualifiedIdType() ||
00070       PT->isObjCClassType() || PT->isObjCQualifiedClassType())
00071     return true;
00072   
00073   // Does the interface subclass NSObject?
00074   // FIXME: We can memoize here if this gets too expensive.
00075   const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();
00076   
00077   // Assume that anything declared with a forward declaration and no
00078   // @interface subclasses NSObject.
00079   if (!ID->hasDefinition())
00080     return true;
00081   
00082   for ( ; ID ; ID = ID->getSuperClass())
00083     if (ID->getIdentifier()->getName() == "NSObject")
00084       return true;
00085   
00086   return false;
00087 }
00088 
00089 bool coreFoundation::followsCreateRule(const FunctionDecl *fn) {
00090   // For now, *just* base this on the function name, not on anything else.
00091 
00092   const IdentifierInfo *ident = fn->getIdentifier();
00093   if (!ident) return false;
00094   StringRef functionName = ident->getName();
00095   
00096   StringRef::iterator it = functionName.begin();
00097   StringRef::iterator start = it;
00098   StringRef::iterator endI = functionName.end();
00099     
00100   while (true) {
00101     // Scan for the start of 'create' or 'copy'.
00102     for ( ; it != endI ; ++it) {
00103       // Search for the first character.  It can either be 'C' or 'c'.
00104       char ch = *it;
00105       if (ch == 'C' || ch == 'c') {
00106         // Make sure this isn't something like 'recreate' or 'Scopy'.
00107         if (ch == 'c' && it != start && isalpha(*(it - 1)))
00108           continue;
00109 
00110         ++it;
00111         break;
00112       }
00113     }
00114 
00115     // Did we hit the end of the string?  If so, we didn't find a match.
00116     if (it == endI)
00117       return false;
00118     
00119     // Scan for *lowercase* 'reate' or 'opy', followed by no lowercase
00120     // character.
00121     StringRef suffix = functionName.substr(it - start);
00122     if (suffix.startswith("reate")) {
00123       it += 5;
00124     }
00125     else if (suffix.startswith("opy")) {
00126       it += 3;
00127     } else {
00128       // Keep scanning.
00129       continue;
00130     }
00131     
00132     if (it == endI || !islower(*it))
00133       return true;
00134   
00135     // If we matched a lowercase character, it isn't the end of the
00136     // word.  Keep scanning.
00137   }
00138 }