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