Index: clang/include/clang/Analysis/RetainSummaryManager.h =================================================================== --- clang/include/clang/Analysis/RetainSummaryManager.h +++ clang/include/clang/Analysis/RetainSummaryManager.h @@ -12,25 +12,21 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_ANALYZER_CORE_RETAINSUMMARYMANAGER -#define LLVM_CLANG_ANALYZER_CORE_RETAINSUMMARYMANAGER +#ifndef LLVM_CLANG_ANALYSIS_RETAINSUMMARY_MANAGER_H +#define LLVM_CLANG_ANALYSIS_RETAINSUMMARY_MANAGER_H #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/ImmutableMap.h" #include "clang/AST/Attr.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/ParentMap.h" +#include "clang/Analysis/AnyCall.h" #include "clang/Analysis/SelectorExtras.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include "llvm/ADT/STLExtras.h" -//===----------------------------------------------------------------------===// -// Adapters for FoldingSet. -//===----------------------------------------------------------------------===// - using namespace clang; -using namespace ento; namespace clang { namespace ento { @@ -262,9 +258,13 @@ } // end namespace ento } // end namespace clang +using namespace ento; namespace llvm { +//===----------------------------------------------------------------------===// +// Adapters for FoldingSet. +//===----------------------------------------------------------------------===// template <> struct FoldingSetTrait { static inline void Profile(const ArgEffect X, FoldingSetNodeID &ID) { ID.AddInteger((unsigned) X.getKind()); @@ -653,19 +653,15 @@ RetainSummaryTemplate &Template); public: - RetainSummaryManager(ASTContext &ctx, - bool usesARC, - bool trackObjCAndCFObjects, + RetainSummaryManager(ASTContext &ctx, bool trackObjCAndCFObjects, bool trackOSObjects) - : Ctx(ctx), - ARCEnabled(usesARC), - TrackObjCAndCFObjects(trackObjCAndCFObjects), - TrackOSObjects(trackOSObjects), - AF(BPAlloc), - ObjCAllocRetE(usesARC ? RetEffect::MakeNotOwned(ObjKind::ObjC) - : RetEffect::MakeOwned(ObjKind::ObjC)), - ObjCInitRetE(usesARC ? RetEffect::MakeNotOwned(ObjKind::ObjC) - : RetEffect::MakeOwnedWhenTrackedReceiver()) { + : Ctx(ctx), ARCEnabled((bool)Ctx.getLangOpts().ObjCAutoRefCount), + TrackObjCAndCFObjects(trackObjCAndCFObjects), + TrackOSObjects(trackOSObjects), AF(BPAlloc), + ObjCAllocRetE(ARCEnabled ? RetEffect::MakeNotOwned(ObjKind::ObjC) + : RetEffect::MakeOwned(ObjKind::ObjC)), + ObjCInitRetE(ARCEnabled ? RetEffect::MakeNotOwned(ObjKind::ObjC) + : RetEffect::MakeOwnedWhenTrackedReceiver()) { InitializeClassMethodSummaries(); InitializeMethodSummaries(); } @@ -693,43 +689,29 @@ bool isTrustedReferenceCountImplementation(const FunctionDecl *FD); - const RetainSummary *getSummary(const CallEvent &Call, + const RetainSummary *getSummary(AnyCall C, + bool HasNonZeroCallbackArg, + bool IsReceiverUnconsumedSelf, QualType ReceiverType=QualType()); + /// getMethodSummary - This version of getMethodSummary is used to query + /// the summary for the current method being analyzed. + const RetainSummary *getMethodSummary(const ObjCMethodDecl *MD); + const RetainSummary *getFunctionSummary(const FunctionDecl *FD); + RetEffect getObjAllocRetEffect() const { return ObjCAllocRetE; } + +private: const RetainSummary *getMethodSummary(Selector S, const ObjCInterfaceDecl *ID, const ObjCMethodDecl *MD, QualType RetTy, ObjCMethodSummariesTy &CachedSummaries); const RetainSummary * - getInstanceMethodSummary(const ObjCMethodCall &M, - QualType ReceiverType); - - const RetainSummary *getClassMethodSummary(const ObjCMethodCall &M) { - assert(!M.isInstanceMessage()); - const ObjCInterfaceDecl *Class = M.getReceiverInterface(); - - return getMethodSummary(M.getSelector(), Class, M.getDecl(), - M.getResultType(), ObjCClassMethodSummaries); - } - - /// getMethodSummary - This version of getMethodSummary is used to query - /// the summary for the current method being analyzed. - const RetainSummary *getMethodSummary(const ObjCMethodDecl *MD) { - const ObjCInterfaceDecl *ID = MD->getClassInterface(); - Selector S = MD->getSelector(); - QualType ResultTy = MD->getReturnType(); + getInstanceMethodSummary(const ObjCMessageExpr *ME, QualType ReceiverType); - ObjCMethodSummariesTy *CachedSummaries; - if (MD->isInstanceMethod()) - CachedSummaries = &ObjCMethodSummaries; - else - CachedSummaries = &ObjCClassMethodSummaries; - - return getMethodSummary(S, ID, MD, ResultTy, *CachedSummaries); - } + const RetainSummary *getClassMethodSummary(const ObjCMessageExpr *ME); const RetainSummary *getStandardMethodSummary(const ObjCMethodDecl *MD, Selector S, QualType RetTy); @@ -744,13 +726,10 @@ void updateSummaryFromAnnotations(const RetainSummary *&Summ, const FunctionDecl *FD); - void updateSummaryForCall(const RetainSummary *&Summ, - const CallEvent &Call); - - bool isARCEnabled() const { return ARCEnabled; } - - RetEffect getObjAllocRetEffect() const { return ObjCAllocRetE; } + AnyCall C, + bool HasNonZeroCallbackArg, + bool IsReceiverUnconsumedSelf); /// Determine whether a declaration {@code D} of correspondent type (return /// type for functions/methods) {@code QT} has any of the given attributes, Index: clang/lib/ARCMigrate/CMakeLists.txt =================================================================== --- clang/lib/ARCMigrate/CMakeLists.txt +++ clang/lib/ARCMigrate/CMakeLists.txt @@ -34,6 +34,4 @@ clangRewrite clangSema clangSerialization - clangStaticAnalyzerCheckers - clangStaticAnalyzerCore ) Index: clang/lib/ARCMigrate/ObjCMT.cpp =================================================================== --- clang/lib/ARCMigrate/ObjCMT.cpp +++ clang/lib/ARCMigrate/ObjCMT.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "Transforms.h" +#include "clang/Analysis/RetainSummaryManager.h" #include "clang/ARCMigrate/ARCMT.h" #include "clang/ARCMigrate/ARCMTActions.h" #include "clang/AST/ASTConsumer.h" @@ -26,7 +27,6 @@ #include "clang/Lex/PPConditionalDirectiveRecord.h" #include "clang/Lex/Preprocessor.h" #include "clang/Rewrite/Core/Rewriter.h" -#include "clang/StaticAnalyzer/Core/RetainSummaryManager.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringSet.h" #include "llvm/Support/Path.h" Index: clang/lib/Analysis/CMakeLists.txt =================================================================== --- clang/lib/Analysis/CMakeLists.txt +++ clang/lib/Analysis/CMakeLists.txt @@ -21,6 +21,7 @@ PostOrderCFGView.cpp ProgramPoint.cpp ReachableCode.cpp + RetainSummaryManager.cpp ThreadSafety.cpp ThreadSafetyCommon.cpp ThreadSafetyLogical.cpp Index: clang/lib/Analysis/RetainSummaryManager.cpp =================================================================== --- clang/lib/Analysis/RetainSummaryManager.cpp +++ clang/lib/Analysis/RetainSummaryManager.cpp @@ -12,8 +12,8 @@ // //===----------------------------------------------------------------------===// -#include "clang/StaticAnalyzer/Core/RetainSummaryManager.h" #include "clang/Analysis/DomainSpecific/CocoaConventions.h" +#include "clang/Analysis/RetainSummaryManager.h" #include "clang/AST/Attr.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" @@ -558,8 +558,11 @@ } void RetainSummaryManager::updateSummaryForCall(const RetainSummary *&S, - const CallEvent &Call) { - if (Call.hasNonZeroCallbackArg()) { + AnyCall C, + bool HasNonZeroCallbackArg, + bool IsReceiverUnconsumedSelf) { + + if (HasNonZeroCallbackArg) { ArgEffect RecEffect = getStopTrackingHardEquivalent(S->getReceiverEffect()); ArgEffect DefEffect = @@ -580,8 +583,8 @@ // Special cases where the callback argument CANNOT free the return value. // This can generally only happen if we know that the callback will only be // called when the return value is already being deallocated. - if (const SimpleFunctionCall *FC = dyn_cast(&Call)) { - if (IdentifierInfo *Name = FC->getDecl()->getIdentifier()) { + if (C.getKind() == AnyCall::Function) { + if (const IdentifierInfo *Name = C.getIdentifier()) { // When the CGBitmapContext is deallocated, the callback here will free // the associated data buffer. // The callback in dispatch_data_create frees the buffer, but not @@ -607,50 +610,42 @@ // Note, we don't want to just stop tracking the value since we want the // RetainCount checker to report leaks and use-after-free if SelfInit checker // is turned off. - if (const ObjCMethodCall *MC = dyn_cast(&Call)) { - if (MC->getMethodFamily() == OMF_init && MC->isReceiverSelfOrSuper()) { - - // Check if the message is not consumed, we know it will not be used in - // an assignment, ex: "self = [super init]". - const Expr *ME = MC->getOriginExpr(); - const LocationContext *LCtx = MC->getLocationContext(); - ParentMap &PM = LCtx->getAnalysisDeclContext()->getParentMap(); - if (!PM.isConsumedExpr(ME)) { - RetainSummaryTemplate ModifiableSummaryTemplate(S, *this); - ModifiableSummaryTemplate->setReceiverEffect(ArgEffect(DoNothing)); - ModifiableSummaryTemplate->setRetEffect(RetEffect::MakeNoRet()); - } - } + if (IsReceiverUnconsumedSelf) { + RetainSummaryTemplate ModifiableSummaryTemplate(S, *this); + ModifiableSummaryTemplate->setReceiverEffect(ArgEffect(DoNothing)); + ModifiableSummaryTemplate->setRetEffect(RetEffect::MakeNoRet()); } } const RetainSummary * -RetainSummaryManager::getSummary(const CallEvent &Call, +RetainSummaryManager::getSummary(AnyCall C, + bool HasNonZeroCallbackArg, + bool IsReceiverUnconsumedSelf, QualType ReceiverType) { const RetainSummary *Summ; - switch (Call.getKind()) { - case CE_Function: - case CE_CXXMember: - case CE_CXXMemberOperator: - case CE_CXXConstructor: - case CE_CXXAllocator: - Summ = getFunctionSummary(cast_or_null(Call.getDecl())); + switch (C.getKind()) { + case AnyCall::Function: + case AnyCall::Constructor: + case AnyCall::Allocator: + case AnyCall::Deallocator: + Summ = getFunctionSummary(cast_or_null(C.getDecl())); break; - case CE_Block: - case CE_CXXDestructor: + case AnyCall::Block: + case AnyCall::Destructor: // FIXME: These calls are currently unsupported. return getPersistentStopSummary(); - case CE_ObjCMessage: { - const ObjCMethodCall &Msg = cast(Call); - if (Msg.isInstanceMessage()) - Summ = getInstanceMethodSummary(Msg, ReceiverType); + case AnyCall::ObjCMethod: { + const auto *ME = cast(C.getExpr()); + if (ME->isInstanceMessage()) + Summ = getInstanceMethodSummary(ME, ReceiverType); else - Summ = getClassMethodSummary(Msg); + Summ = getClassMethodSummary(ME); break; } } - updateSummaryForCall(Summ, Call); + updateSummaryForCall(Summ, C, HasNonZeroCallbackArg, + IsReceiverUnconsumedSelf); assert(Summ && "Unknown call type?"); return Summ; @@ -1067,8 +1062,17 @@ ArgEffect(ReceiverEff), ArgEffect(MayEscape)); } +const RetainSummary * +RetainSummaryManager::getClassMethodSummary(const ObjCMessageExpr *ME) { + assert(!ME->isInstanceMessage()); + const ObjCInterfaceDecl *Class = ME->getReceiverInterface(); + + return getMethodSummary(ME->getSelector(), Class, ME->getMethodDecl(), + ME->getType(), ObjCClassMethodSummaries); +} + const RetainSummary *RetainSummaryManager::getInstanceMethodSummary( - const ObjCMethodCall &Msg, + const ObjCMessageExpr *ME, QualType ReceiverType) { const ObjCInterfaceDecl *ReceiverClass = nullptr; @@ -1080,18 +1084,18 @@ // If we don't know what kind of object this is, fall back to its static type. if (!ReceiverClass) - ReceiverClass = Msg.getReceiverInterface(); + ReceiverClass = ME->getReceiverInterface(); // FIXME: The receiver could be a reference to a class, meaning that // we should use the class method. // id x = [NSObject class]; // [x performSelector:... withObject:... afterDelay:...]; - Selector S = Msg.getSelector(); - const ObjCMethodDecl *Method = Msg.getDecl(); + Selector S = ME->getSelector(); + const ObjCMethodDecl *Method = ME->getMethodDecl(); if (!Method && ReceiverClass) Method = ReceiverClass->getInstanceMethod(S); - return getMethodSummary(S, ReceiverClass, Method, Msg.getResultType(), + return getMethodSummary(S, ReceiverClass, Method, ME->getType(), ObjCMethodSummaries); } @@ -1220,10 +1224,24 @@ addInstMethSummary("CIContext", CFAllocSumm, "createCGLayerWithSize", "info"); } +const RetainSummary * +RetainSummaryManager::getMethodSummary(const ObjCMethodDecl *MD) { + const ObjCInterfaceDecl *ID = MD->getClassInterface(); + Selector S = MD->getSelector(); + QualType ResultTy = MD->getReturnType(); + + ObjCMethodSummariesTy *CachedSummaries; + if (MD->isInstanceMethod()) + CachedSummaries = &ObjCMethodSummaries; + else + CachedSummaries = &ObjCClassMethodSummaries; + + return getMethodSummary(S, ID, MD, ResultTy, *CachedSummaries); +} + CallEffects CallEffects::getEffect(const ObjCMethodDecl *MD) { ASTContext &Ctx = MD->getASTContext(); - LangOptions L = Ctx.getLangOpts(); - RetainSummaryManager M(Ctx, L.ObjCAutoRefCount, + RetainSummaryManager M(Ctx, /*TrackNSAndCFObjects=*/true, /*TrackOSObjects=*/false); const RetainSummary *S = M.getMethodSummary(MD); @@ -1237,8 +1255,7 @@ CallEffects CallEffects::getEffect(const FunctionDecl *FD) { ASTContext &Ctx = FD->getASTContext(); - LangOptions L = Ctx.getLangOpts(); - RetainSummaryManager M(Ctx, L.ObjCAutoRefCount, + RetainSummaryManager M(Ctx, /*TrackNSAndCFObjects=*/true, /*TrackOSObjects=*/false); const RetainSummary *S = M.getFunctionSummary(FD); Index: clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.h =================================================================== --- clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.h +++ clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.h @@ -21,6 +21,7 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/ParentMap.h" #include "clang/Analysis/DomainSpecific/CocoaConventions.h" +#include "clang/Analysis/RetainSummaryManager.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/SourceManager.h" #include "clang/Analysis/SelectorExtras.h" @@ -32,7 +33,6 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h" -#include "clang/StaticAnalyzer/Core/RetainSummaryManager.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/ImmutableList.h" @@ -275,15 +275,9 @@ RetainCountChecker() {}; RetainSummaryManager &getSummaryManager(ASTContext &Ctx) const { - // FIXME: We don't support ARC being turned on and off during one analysis. - // (nor, for that matter, do we support changing ASTContexts) - bool ARCEnabled = (bool)Ctx.getLangOpts().ObjCAutoRefCount; - if (!Summaries) { - Summaries.reset(new RetainSummaryManager( - Ctx, ARCEnabled, TrackObjCAndCFObjects, TrackOSObjects)); - } else { - assert(Summaries->isARCEnabled() == ARCEnabled); - } + if (!Summaries) + Summaries.reset( + new RetainSummaryManager(Ctx, TrackObjCAndCFObjects, TrackOSObjects)); return *Summaries; } Index: clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp +++ clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "RetainCountChecker.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" using namespace clang; using namespace ento; @@ -326,6 +327,31 @@ C.addTransition(State); } +static bool isReceiverUnconsumedSelf(const CallEvent &Call) { + if (const auto *MC = dyn_cast(&Call)) { + + // Check if the message is not consumed, we know it will not be used in + // an assignment, ex: "self = [super init]". + return MC->getMethodFamily() == OMF_init && MC->isReceiverSelfOrSuper() && + !Call.getLocationContext() + ->getAnalysisDeclContext() + ->getParentMap() + .isConsumedExpr(Call.getOriginExpr()); + } + return false; +} + +const static RetainSummary *getSummary(RetainSummaryManager &Summaries, + const CallEvent &Call, + QualType ReceiverType) { + const Expr *CE = Call.getOriginExpr(); + AnyCall C = + CE ? AnyCall(CE) + : AnyCall::forDestructorCall(cast(Call.getDecl())); + return Summaries.getSummary(C, Call.hasNonZeroCallbackArg(), + isReceiverUnconsumedSelf(Call), ReceiverType); +} + void RetainCountChecker::checkPostCall(const CallEvent &Call, CheckerContext &C) const { RetainSummaryManager &Summaries = getSummaryManager(C); @@ -341,7 +367,7 @@ } } - const RetainSummary *Summ = Summaries.getSummary(Call, ReceiverType); + const RetainSummary *Summ = getSummary(Summaries, Call, ReceiverType); if (C.wasInlined) { processSummaryOfInlined(*Summ, Call, C); Index: clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.h =================================================================== --- clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.h +++ clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.h @@ -14,10 +14,11 @@ #ifndef LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_RETAINCOUNTCHECKER_DIAGNOSTICS_H #define LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_RETAINCOUNTCHECKER_DIAGNOSTICS_H +#include "clang/Analysis/RetainSummaryManager.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h" #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" -#include "clang/StaticAnalyzer/Core/RetainSummaryManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" namespace clang { namespace ento { Index: clang/lib/StaticAnalyzer/Core/CMakeLists.txt =================================================================== --- clang/lib/StaticAnalyzer/Core/CMakeLists.txt +++ clang/lib/StaticAnalyzer/Core/CMakeLists.txt @@ -43,7 +43,6 @@ RangeConstraintManager.cpp RangedConstraintManager.cpp RegionStore.cpp - RetainSummaryManager.cpp SarifDiagnostics.cpp SimpleConstraintManager.cpp SimpleSValBuilder.cpp