From 71c080f6252f0364eb41170dcbcc277ae4311857 Mon Sep 17 00:00:00 2001 From: Ted Kremenek Date: Wed, 14 Aug 2013 23:41:49 +0000 Subject: [PATCH] [static analyzer] add a simple "CallEffects" API to query the retain count semantics of a method. This is intended to be a simplified API, whose internals are deliberately less efficient for the purpose of a simplified interface, for use with clients that want to query the analyzer's heuristics for determining retain count semantics. There are no immediate clients, but it is intended to be used by the ObjC modernizer. llvm-svn: 188433 --- .../StaticAnalyzer/Checkers/ObjCRetainCount.h | 34 +++++++++++++- .../Checkers/RetainCountChecker.cpp | 44 +++++++++++++++++++ 2 files changed, 77 insertions(+), 1 deletion(-) 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 + +}}}