diff --git a/clang/include/clang/StaticAnalyzer/Checkers/ObjCRetainCount.h b/clang/include/clang/StaticAnalyzer/Checkers/ObjCRetainCount.h index eed6b1f7e8c9..ef45d6c3269a 100644 --- a/clang/include/clang/StaticAnalyzer/Checkers/ObjCRetainCount.h +++ b/clang/include/clang/StaticAnalyzer/Checkers/ObjCRetainCount.h @@ -180,7 +180,39 @@ public: return RetEffect(NoRetHard); } }; - + +/// Encapsulates the retain count semantics on the arguments, return value, +/// and receiver (if any) of a function/method call. +/// +/// Note that construction of these objects is not highly efficient. That +/// is okay for clients where creating these objects isn't really a bottleneck. +/// The purpose of the API is to provide something simple. The actual +/// static analyzer checker that implements retain/release typestate +/// tracking uses something more efficient. +class CallEffects { + llvm::SmallVector Args; + RetEffect Ret; + ArgEffect Receiver; + + CallEffects(const RetEffect &R) : Ret(R) {} + +public: + /// Returns the argument effects for a call. + llvm::ArrayRef getArgs() const { return Args; } + + /// Returns the effects on the receiver. + ArgEffect getReceiver() const { return Receiver; } + + /// Returns the effect on the return value. + RetEffect getReturnValue() const { return Ret; } + + /// Return the CallEfect for a given Objective-C method. + static CallEffects getEffect(const ObjCMethodDecl *MD); + + /// Return the CallEfect for a given C/C++ function. + static CallEffects getEffect(const FunctionDecl *FD); +}; + }}} #endif diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp index f337a903e983..1a1fa4e2e9a0 100644 --- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp @@ -317,6 +317,16 @@ public: return DefaultArgEffect; } + + /// Return the number of argument effects. This is O(n) in the number + /// of arguments. + unsigned getNumArgs() const { + unsigned N = 0; + for (ArgEffects::iterator I = Args.begin(), E = Args.end(); I != E; ++I) { + ++N; + }; + return N; + } void addArg(ArgEffects::Factory &af, unsigned idx, ArgEffect e) { Args = af.add(Args, idx, e); @@ -3675,3 +3685,37 @@ void ento::registerRetainCountChecker(CheckerManager &Mgr) { Mgr.registerChecker(Mgr.getAnalyzerOptions()); } +//===----------------------------------------------------------------------===// +// Implementation of the CallEffects API. +//===----------------------------------------------------------------------===// + +namespace clang { namespace ento { namespace objc_retain { + +// This is a bit gross, but it allows us to populate CallEffects without +// creating a bunch of accessors. This kind is very localized, so the +// damage of this macro is limited. +#define createCallEffect(D, KIND)\ + ASTContext &Ctx = D->getASTContext();\ + LangOptions L = Ctx.getLangOpts();\ + RetainSummaryManager M(Ctx, L.GCOnly, L.ObjCAutoRefCount);\ + const RetainSummary *S = M.get ## KIND ## Summary(D);\ + CallEffects CE(S->getRetEffect());\ + CE.Receiver = S->getReceiverEffect();\ + unsigned N = S->getNumArgs();\ + for (unsigned i = 0; i < N; ++i) {\ + CE.Args.push_back(S->getArg(i));\ + } + +CallEffects CallEffects::getEffect(const ObjCMethodDecl *MD) { + createCallEffect(MD, Method); + return CE; +} + +CallEffects CallEffects::getEffect(const FunctionDecl *FD) { + createCallEffect(FD, Function); + return CE; +} + +#undef createCallEffect + +}}}