Newer
Older
// CFRefCount.cpp - Transfer functions for tracking simple values -*- C++ -*--//
Ted Kremenek
committed
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the methods for CFRefCount, which implements
Ted Kremenek
committed
// a reference count checker for Core Foundation (Mac OS X).
//
//===----------------------------------------------------------------------===//
#include "GRSimpleVals.h"
#include "clang/Basic/LangOptions.h"
Ted Kremenek
committed
#include "clang/Basic/SourceManager.h"
Ted Kremenek
committed
#include "clang/Analysis/PathSensitive/ValueState.h"
Ted Kremenek
committed
#include "clang/Analysis/PathDiagnostic.h"
Ted Kremenek
committed
#include "clang/Analysis/LocalCheckers.h"
Ted Kremenek
committed
#include "clang/Analysis/PathDiagnostic.h"
#include "clang/Analysis/PathSensitive/BugReporter.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/ImmutableMap.h"
Ted Kremenek
committed
#include "llvm/ADT/StringExtras.h"
Ted Kremenek
committed
#include "llvm/Support/Compiler.h"
#include "llvm/ADT/STLExtras.h"
Ted Kremenek
committed
#include <ostream>
Ted Kremenek
committed
using namespace clang;
Ted Kremenek
committed
using llvm::CStrInCStrNoCase;
Ted Kremenek
committed
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
static inline Selector GetNullarySelector(const char* name, ASTContext& Ctx) {
IdentifierInfo* II = &Ctx.Idents.get(name);
return Ctx.Selectors.getSelector(0, &II);
}
static inline Selector GetUnarySelector(const char* name, ASTContext& Ctx) {
IdentifierInfo* II = &Ctx.Idents.get(name);
return Ctx.Selectors.getSelector(1, &II);
}
//===----------------------------------------------------------------------===//
// Type querying functions.
//===----------------------------------------------------------------------===//
static bool isCFRefType(QualType T) {
if (!T->isPointerType())
return false;
// Check the typedef for the name "CF" and the substring "Ref".
TypedefType* TD = dyn_cast<TypedefType>(T.getTypePtr());
if (!TD)
return false;
const char* TDName = TD->getDecl()->getIdentifier()->getName();
assert (TDName);
if (TDName[0] != 'C' || TDName[1] != 'F')
return false;
if (strstr(TDName, "Ref") == 0)
return false;
return true;
}
static bool isCGRefType(QualType T) {
if (!T->isPointerType())
return false;
// Check the typedef for the name "CG" and the substring "Ref".
TypedefType* TD = dyn_cast<TypedefType>(T.getTypePtr());
if (!TD)
return false;
const char* TDName = TD->getDecl()->getIdentifier()->getName();
assert (TDName);
if (TDName[0] != 'C' || TDName[1] != 'G')
return false;
if (strstr(TDName, "Ref") == 0)
return false;
return true;
}
static bool isNSType(QualType T) {
if (!T->isPointerType())
return false;
ObjCInterfaceType* OT = dyn_cast<ObjCInterfaceType>(T.getTypePtr());
if (!OT)
return false;
const char* ClsName = OT->getDecl()->getIdentifier()->getName();
assert (ClsName);
if (ClsName[0] != 'N' || ClsName[1] != 'S')
return false;
return true;
}
//===----------------------------------------------------------------------===//
// Primitives used for constructing summaries for function/method calls.
//===----------------------------------------------------------------------===//
namespace {
/// ArgEffect is used to summarize a function/method call's effect on a
/// particular argument.
enum ArgEffect { IncRef, DecRef, DoNothing, DoNothingByRef,
StopTracking, MayEscape, SelfOwn, Autorelease };
/// ArgEffects summarizes the effects of a function/method call on all of
/// its arguments.
typedef std::vector<std::pair<unsigned,ArgEffect> > ArgEffects;
Ted Kremenek
committed
namespace llvm {
template <> struct FoldingSetTrait<ArgEffects> {
static void Profile(const ArgEffects& X, FoldingSetNodeID& ID) {
for (ArgEffects::const_iterator I = X.begin(), E = X.end(); I!= E; ++I) {
ID.AddInteger(I->first);
ID.AddInteger((unsigned) I->second);
}
}
};
} // end llvm namespace
namespace {
/// RetEffect is used to summarize a function/method call's behavior with
/// respect to its return value.
class VISIBILITY_HIDDEN RetEffect {
enum Kind { NoRet, Alias, OwnedSymbol, OwnedAllocatedSymbol,
NotOwnedSymbol, ReceiverAlias };
private:
unsigned Data;
RetEffect(Kind k, unsigned D = 0) { Data = (D << 3) | (unsigned) k; }
Kind getKind() const { return (Kind) (Data & 0x7); }
assert(getKind() == Alias);
return Data >> 3;
static RetEffect MakeAlias(unsigned Idx) {
return RetEffect(Alias, Idx);
}
static RetEffect MakeReceiverAlias() {
return RetEffect(ReceiverAlias);
}
static RetEffect MakeOwned(bool isAllocated = false) {
return RetEffect(isAllocated ? OwnedAllocatedSymbol : OwnedSymbol);
}
static RetEffect MakeNotOwned() {
return RetEffect(NotOwnedSymbol);
}
static RetEffect MakeNoRet() {
return RetEffect(NoRet);
}
void Profile(llvm::FoldingSetNodeID& ID) const {
ID.AddInteger(Data);
}
class VISIBILITY_HIDDEN RetainSummary : public llvm::FoldingSetNode {
Ted Kremenek
committed
/// Args - an ordered vector of (index, ArgEffect) pairs, where index
/// specifies the argument (starting from 0). This can be sparsely
/// populated; arguments with no entry in Args use 'DefaultArgEffect'.
ArgEffects* Args;
Ted Kremenek
committed
/// DefaultArgEffect - The default ArgEffect to apply to arguments that
/// do not have an entry in Args.
ArgEffect DefaultArgEffect;
/// Receiver - If this summary applies to an Objective-C message expression,
/// this is the effect applied to the state of the receiver.
/// Ret - The effect on the return value. Used to indicate if the
/// function/method call returns a new tracked symbol, returns an
/// alias of one of the arguments in the call, and so on.
Ted Kremenek
committed
RetainSummary(ArgEffects* A, RetEffect R, ArgEffect defaultEff,
ArgEffect ReceiverEff)
: Args(A), DefaultArgEffect(defaultEff), Receiver(ReceiverEff), Ret(R) {}
/// getArg - Return the argument effect on the argument specified by
/// idx (starting from 0).
ArgEffect getArg(unsigned idx) const {
Ted Kremenek
committed
Ted Kremenek
committed
if (!Args)
Ted Kremenek
committed
return DefaultArgEffect;
Ted Kremenek
committed
// If Args is present, it is likely to contain only 1 element.
// Just do a linear search. Do it from the back because functions with
// large numbers of arguments will be tail heavy with respect to which
// argument they actually modify with respect to the reference count.
Ted Kremenek
committed
for (ArgEffects::reverse_iterator I=Args->rbegin(), E=Args->rend();
I!=E; ++I) {
if (idx > I->first)
Ted Kremenek
committed
return DefaultArgEffect;
Ted Kremenek
committed
if (idx == I->first)
return I->second;
}
Ted Kremenek
committed
return DefaultArgEffect;
/// getRetEffect - Returns the effect on the return value of the call.
RetEffect getRetEffect() const {
return Ret;
}
/// getReceiverEffect - Returns the effect on the receiver of the call.
/// This is only meaningful if the summary applies to an ObjCMessageExpr*.
ArgEffect getReceiverEffect() const {
return Receiver;
}
typedef ArgEffects::const_iterator ExprIterator;
ExprIterator begin_args() const { return Args->begin(); }
ExprIterator end_args() const { return Args->end(); }
Ted Kremenek
committed
static void Profile(llvm::FoldingSetNodeID& ID, ArgEffects* A,
Ted Kremenek
committed
RetEffect RetEff, ArgEffect DefaultEff,
ArgEffect ReceiverEff) {
ID.AddPointer(A);
Ted Kremenek
committed
ID.AddInteger((unsigned) DefaultEff);
ID.AddInteger((unsigned) ReceiverEff);
}
void Profile(llvm::FoldingSetNodeID& ID) const {
Ted Kremenek
committed
Profile(ID, Args, Ret, DefaultArgEffect, Receiver);
} // end anonymous namespace
//===----------------------------------------------------------------------===//
// Data structures for constructing summaries.
//===----------------------------------------------------------------------===//
namespace {
class VISIBILITY_HIDDEN ObjCSummaryKey {
IdentifierInfo* II;
Selector S;
public:
ObjCSummaryKey(IdentifierInfo* ii, Selector s)
: II(ii), S(s) {}
ObjCSummaryKey(ObjCInterfaceDecl* d, Selector s)
: II(d ? d->getIdentifier() : 0), S(s) {}
ObjCSummaryKey(Selector s)
: II(0), S(s) {}
IdentifierInfo* getIdentifier() const { return II; }
Selector getSelector() const { return S; }
};
}
namespace llvm {
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
template <> struct DenseMapInfo<ObjCSummaryKey> {
static inline ObjCSummaryKey getEmptyKey() {
return ObjCSummaryKey(DenseMapInfo<IdentifierInfo*>::getEmptyKey(),
DenseMapInfo<Selector>::getEmptyKey());
}
static inline ObjCSummaryKey getTombstoneKey() {
return ObjCSummaryKey(DenseMapInfo<IdentifierInfo*>::getTombstoneKey(),
DenseMapInfo<Selector>::getTombstoneKey());
}
static unsigned getHashValue(const ObjCSummaryKey &V) {
return (DenseMapInfo<IdentifierInfo*>::getHashValue(V.getIdentifier())
& 0x88888888)
| (DenseMapInfo<Selector>::getHashValue(V.getSelector())
& 0x55555555);
}
static bool isEqual(const ObjCSummaryKey& LHS, const ObjCSummaryKey& RHS) {
return DenseMapInfo<IdentifierInfo*>::isEqual(LHS.getIdentifier(),
RHS.getIdentifier()) &&
DenseMapInfo<Selector>::isEqual(LHS.getSelector(),
RHS.getSelector());
}
static bool isPod() {
return DenseMapInfo<ObjCInterfaceDecl*>::isPod() &&
DenseMapInfo<Selector>::isPod();
}
};
} // end llvm namespace
namespace {
class VISIBILITY_HIDDEN ObjCSummaryCache {
typedef llvm::DenseMap<ObjCSummaryKey, RetainSummary*> MapTy;
MapTy M;
public:
ObjCSummaryCache() {}
typedef MapTy::iterator iterator;
iterator find(ObjCInterfaceDecl* D, Selector S) {
// Do a lookup with the (D,S) pair. If we find a match return
// the iterator.
ObjCSummaryKey K(D, S);
MapTy::iterator I = M.find(K);
if (I != M.end() || !D)
return I;
// Walk the super chain. If we find a hit with a parent, we'll end
// up returning that summary. We actually allow that key (null,S), as
// we cache summaries for the null ObjCInterfaceDecl* to allow us to
// generate initial summaries without having to worry about NSObject
// being declared.
// FIXME: We may change this at some point.
for (ObjCInterfaceDecl* C=D->getSuperClass() ;; C=C->getSuperClass()) {
if ((I = M.find(ObjCSummaryKey(C, S))) != M.end())
break;
}
// Cache the summary with original key to make the next lookup faster
// and return the iterator.
M[K] = I->second;
return I;
}
iterator find(Expr* Receiver, Selector S) {
return find(getReceiverDecl(Receiver), S);
}
iterator find(IdentifierInfo* II, Selector S) {
// FIXME: Class method lookup. Right now we dont' have a good way
// of going between IdentifierInfo* and the class hierarchy.
iterator I = M.find(ObjCSummaryKey(II, S));
return I == M.end() ? M.find(ObjCSummaryKey(S)) : I;
}
ObjCInterfaceDecl* getReceiverDecl(Expr* E) {
const PointerType* PT = E->getType()->getAsPointerType();
if (!PT) return 0;
ObjCInterfaceType* OI = dyn_cast<ObjCInterfaceType>(PT->getPointeeType());
if (!OI) return 0;
return OI ? OI->getDecl() : 0;
}
iterator end() { return M.end(); }
RetainSummary*& operator[](ObjCMessageExpr* ME) {
Selector S = ME->getSelector();
if (Expr* Receiver = ME->getReceiver()) {
ObjCInterfaceDecl* OD = getReceiverDecl(Receiver);
return OD ? M[ObjCSummaryKey(OD->getIdentifier(), S)] : M[S];
}
return M[ObjCSummaryKey(ME->getClassName(), S)];
}
RetainSummary*& operator[](ObjCSummaryKey K) {
return M[K];
}
Ted Kremenek
committed
RetainSummary*& operator[](Selector S) {
return M[ ObjCSummaryKey(S) ];
}
};
} // end anonymous namespace
//===----------------------------------------------------------------------===//
// Data structures for managing collections of summaries.
//===----------------------------------------------------------------------===//
namespace {
//==-----------------------------------------------------------------==//
// Typedefs.
//==-----------------------------------------------------------------==//
typedef llvm::FoldingSet<llvm::FoldingSetNodeWrapper<ArgEffects> >
ArgEffectsSetTy;
typedef llvm::FoldingSet<RetainSummary>
SummarySetTy;
typedef llvm::DenseMap<FunctionDecl*, RetainSummary*>
FuncSummariesTy;
typedef ObjCSummaryCache ObjCMethodSummariesTy;
//==-----------------------------------------------------------------==//
// Data.
//==-----------------------------------------------------------------==//
ASTContext& Ctx;
/// NSWindowII - An IdentifierInfo* representing the identifier "NSWindow."
IdentifierInfo* NSWindowII;
Ted Kremenek
committed
/// NSPanelII - An IdentifierInfo* representing the identifier "NSPanel."
IdentifierInfo* NSPanelII;
/// CFDictionaryCreateII - An IdentifierInfo* representing the indentifier
/// "CFDictionaryCreate".
IdentifierInfo* CFDictionaryCreateII;
/// GCEnabled - Records whether or not the analyzed code runs in GC mode.
const bool GCEnabled;
SummarySetTy SummarySet;
/// FuncSummaries - A map from FunctionDecls to summaries.
FuncSummariesTy FuncSummaries;
/// ObjCClassMethodSummaries - A map from selectors (for instance methods)
/// to summaries.
Ted Kremenek
committed
ObjCMethodSummariesTy ObjCClassMethodSummaries;
/// ObjCMethodSummaries - A map from selectors to summaries.
Ted Kremenek
committed
ObjCMethodSummariesTy ObjCMethodSummaries;
ArgEffectsSetTy ArgEffectsSet;
/// BPAlloc - A BumpPtrAllocator used for allocating summaries, ArgEffects,
/// and all other data used by the checker.
llvm::BumpPtrAllocator BPAlloc;
/// ScratchArgs - A holding buffer for construct ArgEffects.
ArgEffects ScratchArgs;
RetainSummary* StopSummary;
//==-----------------------------------------------------------------==//
// Methods.
//==-----------------------------------------------------------------==//
/// getArgEffects - Returns a persistent ArgEffects object based on the
/// data in ScratchArgs.
ArgEffects* getArgEffects();
Ted Kremenek
committed
enum UnaryFuncKind { cfretain, cfrelease, cfmakecollectable };
RetainSummary* getUnarySummary(FunctionDecl* FD, UnaryFuncKind func);
RetainSummary* getNSSummary(FunctionDecl* FD, const char* FName);
RetainSummary* getCFSummary(FunctionDecl* FD, const char* FName);
RetainSummary* getCGSummary(FunctionDecl* FD, const char* FName);
RetainSummary* getCFSummaryCreateRule(FunctionDecl* FD);
RetainSummary* getCFSummaryGetRule(FunctionDecl* FD);
RetainSummary* getCFCreateGetRuleSummary(FunctionDecl* FD, const char* FName);
RetainSummary* getPersistentSummary(ArgEffects* AE, RetEffect RetEff,
Ted Kremenek
committed
ArgEffect ReceiverEff = DoNothing,
Ted Kremenek
committed
ArgEffect DefaultEff = MayEscape);
Ted Kremenek
committed
RetainSummary* getPersistentSummary(RetEffect RE,
Ted Kremenek
committed
ArgEffect ReceiverEff = DoNothing,
Ted Kremenek
committed
ArgEffect DefaultEff = MayEscape) {
Ted Kremenek
committed
return getPersistentSummary(getArgEffects(), RE, ReceiverEff, DefaultEff);
Ted Kremenek
committed
RetainSummary* getPersistentStopSummary() {
if (StopSummary)
return StopSummary;
StopSummary = getPersistentSummary(RetEffect::MakeNoRet(),
StopTracking, StopTracking);
return StopSummary;
Ted Kremenek
committed
}
RetainSummary* getInitMethodSummary(ObjCMessageExpr* ME);
Ted Kremenek
committed
void InitializeClassMethodSummaries();
void InitializeMethodSummaries();
void addNSObjectClsMethSummary(Selector S, RetainSummary *Summ) {
ObjCClassMethodSummaries[S] = Summ;
}
void addNSObjectMethSummary(Selector S, RetainSummary *Summ) {
ObjCMethodSummaries[S] = Summ;
}
void addNSWindowMethSummary(Selector S, RetainSummary *Summ) {
ObjCMethodSummaries[ObjCSummaryKey(NSWindowII, S)] = Summ;
}
Ted Kremenek
committed
void addNSPanelMethSummary(Selector S, RetainSummary *Summ) {
ObjCMethodSummaries[ObjCSummaryKey(NSPanelII, S)] = Summ;
}
RetainSummaryManager(ASTContext& ctx, bool gcenabled)
Ted Kremenek
committed
: Ctx(ctx),
NSWindowII(&ctx.Idents.get("NSWindow")),
NSPanelII(&ctx.Idents.get("NSPanel")),
CFDictionaryCreateII(&ctx.Idents.get("CFDictionaryCreate")),
GCEnabled(gcenabled), StopSummary(0) {
InitializeClassMethodSummaries();
InitializeMethodSummaries();
}
~RetainSummaryManager();
RetainSummary* getSummary(FunctionDecl* FD);
RetainSummary* getMethodSummary(ObjCMessageExpr* ME, ObjCInterfaceDecl* ID);
Ted Kremenek
committed
RetainSummary* getClassMethodSummary(IdentifierInfo* ClsName, Selector S);
bool isGCEnabled() const { return GCEnabled; }
};
} // end anonymous namespace
//===----------------------------------------------------------------------===//
// Implementation of checker data structures.
//===----------------------------------------------------------------------===//
RetainSummaryManager::~RetainSummaryManager() {
Ted Kremenek
committed
// FIXME: The ArgEffects could eventually be allocated from BPAlloc,
// mitigating the need to do explicit cleanup of the
// Argument-Effect summaries.
Ted Kremenek
committed
for (ArgEffectsSetTy::iterator I = ArgEffectsSet.begin(),
E = ArgEffectsSet.end(); I!=E; ++I)
I->getValue().~ArgEffects();
Ted Kremenek
committed
}
ArgEffects* RetainSummaryManager::getArgEffects() {
Ted Kremenek
committed
if (ScratchArgs.empty())
return NULL;
// Compute a profile for a non-empty ScratchArgs.
llvm::FoldingSetNodeID profile;
profile.Add(ScratchArgs);
void* InsertPos;
Ted Kremenek
committed
// Look up the uniqued copy, or create a new one.
llvm::FoldingSetNodeWrapper<ArgEffects>* E =
ArgEffectsSet.FindNodeOrInsertPos(profile, InsertPos);
Ted Kremenek
committed
if (E) {
ScratchArgs.clear();
return &E->getValue();
}
E = (llvm::FoldingSetNodeWrapper<ArgEffects>*)
BPAlloc.Allocate<llvm::FoldingSetNodeWrapper<ArgEffects> >();
new (E) llvm::FoldingSetNodeWrapper<ArgEffects>(ScratchArgs);
ArgEffectsSet.InsertNode(E, InsertPos);
ScratchArgs.clear();
return &E->getValue();
}
RetainSummary*
RetainSummaryManager::getPersistentSummary(ArgEffects* AE, RetEffect RetEff,
Ted Kremenek
committed
ArgEffect ReceiverEff,
ArgEffect DefaultEff) {
Ted Kremenek
committed
// Generate a profile for the summary.
llvm::FoldingSetNodeID profile;
Ted Kremenek
committed
RetainSummary::Profile(profile, AE, RetEff, DefaultEff, ReceiverEff);
Ted Kremenek
committed
// Look up the uniqued summary, or create one if it doesn't exist.
void* InsertPos;
RetainSummary* Summ = SummarySet.FindNodeOrInsertPos(profile, InsertPos);
if (Summ)
return Summ;
Ted Kremenek
committed
// Create the summary and return it.
Summ = (RetainSummary*) BPAlloc.Allocate<RetainSummary>();
Ted Kremenek
committed
new (Summ) RetainSummary(AE, RetEff, DefaultEff, ReceiverEff);
SummarySet.InsertNode(Summ, InsertPos);
return Summ;
}
//===----------------------------------------------------------------------===//
// Summary creation for functions (largely uses of Core Foundation).
//===----------------------------------------------------------------------===//
RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) {
SourceLocation Loc = FD->getLocation();
if (!Loc.isFileID())
return NULL;
Ted Kremenek
committed
// Look up a summary in our cache of FunctionDecls -> Summaries.
FuncSummariesTy::iterator I = FuncSummaries.find(FD);
Ted Kremenek
committed
if (I != FuncSummaries.end())
Ted Kremenek
committed
return I->second;
// No summary. Generate one.
const char* FName = FD->getIdentifier()->getName();
RetainSummary *S = 0;
Ted Kremenek
committed
FunctionType* FT = dyn_cast<FunctionType>(FD->getType());
do {
if (FT) {
QualType T = FT->getResultType();
if (isCFRefType(T)) {
S = getCFSummary(FD, FName);
break;
}
if (isCGRefType(T)) {
S = getCGSummary(FD, FName );
break;
}
}
if (FName[0] == 'C' && FName[1] == 'F')
S = getCFSummary(FD, FName);
else if (FName[0] == 'N' && FName[1] == 'S')
S = getNSSummary(FD, FName);
}
while (0);
Ted Kremenek
committed
FuncSummaries[FD] = S;
Ted Kremenek
committed
return S;
Ted Kremenek
committed
}
RetainSummary* RetainSummaryManager::getNSSummary(FunctionDecl* FD,
Ted Kremenek
committed
FName += 2;
Ted Kremenek
committed
if (strcmp(FName, "MakeCollectable") == 0)
return getUnarySummary(FD, cfmakecollectable);
return 0;
}
static bool isRetain(FunctionDecl* FD, const char* FName) {
Ted Kremenek
committed
const char* loc = strstr(FName, "Retain");
return loc && loc[sizeof("Retain")-1] == '\0';
}
static bool isRelease(FunctionDecl* FD, const char* FName) {
Ted Kremenek
committed
const char* loc = strstr(FName, "Release");
return loc && loc[sizeof("Release")-1] == '\0';
}
RetainSummary* RetainSummaryManager::getCFSummary(FunctionDecl* FD,
Ted Kremenek
committed
if (FName[0] == 'C' && FName[1] == 'F')
FName += 2;
if (isRetain(FD, FName))
Ted Kremenek
committed
return getUnarySummary(FD, cfretain);
if (isRelease(FD, FName))
Ted Kremenek
committed
return getUnarySummary(FD, cfrelease);
if (strcmp(FName, "MakeCollectable") == 0)
Ted Kremenek
committed
return getUnarySummary(FD, cfmakecollectable);
return getCFCreateGetRuleSummary(FD, FName);
}
RetainSummary* RetainSummaryManager::getCGSummary(FunctionDecl* FD,
const char* FName) {
if (FName[0] == 'C' && FName[1] == 'G')
FName += 2;
if (isRelease(FD, FName))
return getUnarySummary(FD, cfrelease);
if (isRetain(FD, FName))
return getUnarySummary(FD, cfretain);
return getCFCreateGetRuleSummary(FD, FName);
}
RetainSummary*
RetainSummaryManager::getCFCreateGetRuleSummary(FunctionDecl* FD,
const char* FName) {
Ted Kremenek
committed
if (strstr(FName, "Create") || strstr(FName, "Copy"))
return getCFSummaryCreateRule(FD);
if (strstr(FName, "Get"))
Ted Kremenek
committed
return getCFSummaryGetRule(FD);
Ted Kremenek
committed
return 0;
RetainSummary*
RetainSummaryManager::getUnarySummary(FunctionDecl* FD, UnaryFuncKind func) {
Ted Kremenek
committed
FunctionTypeProto* FT =
dyn_cast<FunctionTypeProto>(FD->getType().getTypePtr());
Ted Kremenek
committed
if (FT) {
if (FT->getNumArgs() != 1)
return 0;
Ted Kremenek
committed
TypedefType* ArgT = dyn_cast<TypedefType>(FT->getArgType(0).getTypePtr());
Ted Kremenek
committed
if (!ArgT)
return 0;
if (!ArgT->isPointerType())
return NULL;
}
Ted Kremenek
committed
assert (ScratchArgs.empty());
switch (func) {
case cfretain: {
ScratchArgs.push_back(std::make_pair(0, IncRef));
Ted Kremenek
committed
return getPersistentSummary(RetEffect::MakeAlias(0),
DoNothing, DoNothing);
}
case cfrelease: {
ScratchArgs.push_back(std::make_pair(0, DecRef));
Ted Kremenek
committed
return getPersistentSummary(RetEffect::MakeNoRet(),
DoNothing, DoNothing);
}
case cfmakecollectable: {
if (GCEnabled)
ScratchArgs.push_back(std::make_pair(0, DecRef));
Ted Kremenek
committed
return getPersistentSummary(RetEffect::MakeAlias(0),
DoNothing, DoNothing);
}
default:
Ted Kremenek
committed
assert (false && "Not a supported unary function.");
Ted Kremenek
committed
}
RetainSummary* RetainSummaryManager::getCFSummaryCreateRule(FunctionDecl* FD) {
FunctionType* FT =
dyn_cast<FunctionType>(FD->getType().getTypePtr());
Ted Kremenek
committed
if (FT && !isCFRefType(FT->getResultType()))
Ted Kremenek
committed
return getPersistentSummary(RetEffect::MakeNoRet());
Ted Kremenek
committed
assert (ScratchArgs.empty());
if (FD->getIdentifier() == CFDictionaryCreateII) {
ScratchArgs.push_back(std::make_pair(1, DoNothingByRef));
ScratchArgs.push_back(std::make_pair(2, DoNothingByRef));
}
return getPersistentSummary(RetEffect::MakeOwned(true));
RetainSummary* RetainSummaryManager::getCFSummaryGetRule(FunctionDecl* FD) {
FunctionType* FT =
dyn_cast<FunctionType>(FD->getType().getTypePtr());
Ted Kremenek
committed
if (FT) {
QualType RetTy = FT->getResultType();
Ted Kremenek
committed
// FIXME: For now we assume that all pointer types returned are referenced
// counted. Since this is the "Get" rule, we assume non-ownership, which
// works fine for things that are not reference counted. We do this because
// some generic data structures return "void*". We need something better
// in the future.
if (!isCFRefType(RetTy) && !RetTy->isPointerType())
Ted Kremenek
committed
return getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing);
Ted Kremenek
committed
}
// FIXME: Add special-cases for functions that retain/release. For now
// just handle the default case.
Ted Kremenek
committed
assert (ScratchArgs.empty());
Ted Kremenek
committed
return getPersistentSummary(RetEffect::MakeNotOwned(), DoNothing, DoNothing);
//===----------------------------------------------------------------------===//
// Summary creation for Selectors.
//===----------------------------------------------------------------------===//
Ted Kremenek
committed
RetainSummary*
RetainSummaryManager::getInitMethodSummary(ObjCMessageExpr* ME) {
assert(ScratchArgs.empty());
RetainSummary* Summ =
getPersistentSummary(RetEffect::MakeReceiverAlias());
Ted Kremenek
committed
RetainSummary*
RetainSummaryManager::getMethodSummary(ObjCMessageExpr* ME,
ObjCInterfaceDecl* ID) {
Ted Kremenek
committed
Selector S = ME->getSelector();
// Look up a summary in our summary cache.
ObjCMethodSummariesTy::iterator I = ObjCMethodSummaries.find(ID, S);
Ted Kremenek
committed
if (I != ObjCMethodSummaries.end())
if (!ME->getType()->isPointerType())
return 0;
// "initXXX": pass-through for receiver.
const char* s = S.getIdentifierInfoForSlot(0)->getName();
assert (ScratchArgs.empty());
Ted Kremenek
committed
if (strncmp(s, "init", 4) == 0 || strncmp(s, "_init", 5) == 0)
Ted Kremenek
committed
// "copyXXX", "createXXX", "newXXX": allocators.
if (!isNSType(ME->getReceiver()->getType()))
return 0;
if (CStrInCStrNoCase(s, "create") || CStrInCStrNoCase(s, "copy") ||
CStrInCStrNoCase(s, "new")) {
Ted Kremenek
committed
RetEffect E = isGCEnabled() ? RetEffect::MakeNoRet()
: RetEffect::MakeOwned(true);
Ted Kremenek
committed
RetainSummary* Summ = getPersistentSummary(E);
return Summ;
Ted Kremenek
committed
}
Ted Kremenek
committed
RetainSummaryManager::getClassMethodSummary(IdentifierInfo* ClsName,
Selector S) {
// FIXME: Eventually we should properly do class method summaries, but
// it requires us being able to walk the type hierarchy. Unfortunately,
// we cannot do this with just an IdentifierInfo* for the class name.
// Look up a summary in our cache of Selectors -> Summaries.
ObjCMethodSummariesTy::iterator I = ObjCClassMethodSummaries.find(ClsName, S);
Ted Kremenek
committed
if (I != ObjCClassMethodSummaries.end())
Ted Kremenek
committed
void RetainSummaryManager::InitializeClassMethodSummaries() {
assert (ScratchArgs.empty());
RetEffect E = isGCEnabled() ? RetEffect::MakeNoRet()
: RetEffect::MakeOwned(true);
RetainSummary* Summ = getPersistentSummary(E);
// Create the summaries for "alloc", "new", and "allocWithZone:" for
// NSObject and its derivatives.
addNSObjectClsMethSummary(GetNullarySelector("alloc", Ctx), Summ);
addNSObjectClsMethSummary(GetNullarySelector("new", Ctx), Summ);
addNSObjectClsMethSummary(GetUnarySelector("allocWithZone", Ctx), Summ);
}
Ted Kremenek
committed
void RetainSummaryManager::InitializeMethodSummaries() {
Ted Kremenek
committed
assert (ScratchArgs.empty());
// Create the "init" selector. It just acts as a pass-through for the
// receiver.
Ted Kremenek
committed
RetainSummary* InitSumm = getPersistentSummary(RetEffect::MakeReceiverAlias());
addNSObjectMethSummary(GetNullarySelector("init", Ctx), InitSumm);
RetEffect E = isGCEnabled() ? RetEffect::MakeNoRet()
: RetEffect::MakeOwned(true);
Ted Kremenek
committed
RetainSummary* Summ = getPersistentSummary(E);
addNSObjectMethSummary(GetNullarySelector("copy", Ctx), Summ);
Ted Kremenek
committed
// Create the "mutableCopy" selector.
addNSObjectMethSummary(GetNullarySelector("mutableCopy", Ctx), Summ);
// Create the "retain" selector.
E = RetEffect::MakeReceiverAlias();
Summ = getPersistentSummary(E, isGCEnabled() ? DoNothing : IncRef);
addNSObjectMethSummary(GetNullarySelector("retain", Ctx), Summ);
// Create the "release" selector.
Summ = getPersistentSummary(E, isGCEnabled() ? DoNothing : DecRef);
addNSObjectMethSummary(GetNullarySelector("release", Ctx), Summ);
// Create the "drain" selector.
Summ = getPersistentSummary(E, isGCEnabled() ? DoNothing : DecRef);
addNSObjectMethSummary(GetNullarySelector("drain", Ctx), Summ);
// Create the "autorelease" selector.
Ted Kremenek
committed
Summ = getPersistentSummary(E, isGCEnabled() ? DoNothing : Autorelease);
addNSObjectMethSummary(GetNullarySelector("autorelease", Ctx), Summ);
// For NSWindow, allocated objects are (initially) self-owned.
Ted Kremenek
committed
// For NSPanel (which subclasses NSWindow), allocated objects are not
// self-owned.
RetainSummary *NSWindowSumm =
getPersistentSummary(RetEffect::MakeReceiverAlias(), SelfOwn);
// Create the "initWithContentRect:styleMask:backing:defer:" selector.
llvm::SmallVector<IdentifierInfo*, 5> II;
II.push_back(&Ctx.Idents.get("initWithContentRect"));
II.push_back(&Ctx.Idents.get("styleMask"));
II.push_back(&Ctx.Idents.get("backing"));
II.push_back(&Ctx.Idents.get("defer"));
Selector S = Ctx.Selectors.getSelector(II.size(), &II[0]);
Ted Kremenek
committed
addNSWindowMethSummary(S, NSWindowSumm);
addNSPanelMethSummary(S, InitSumm);
// Create the "initWithContentRect:styleMask:backing:defer:screen:" selector.
II.push_back(&Ctx.Idents.get("screen"));
S = Ctx.Selectors.getSelector(II.size(), &II[0]);
Ted Kremenek
committed
addNSWindowMethSummary(S, NSWindowSumm);
addNSPanelMethSummary(S, InitSumm);
Ted Kremenek
committed
}
//===----------------------------------------------------------------------===//
Ted Kremenek
committed
// Reference-counting logic (typestate + counts).
//===----------------------------------------------------------------------===//
namespace {