diff --git a/clang/include/clang/Analysis/RetainSummaryManager.h b/clang/include/clang/Analysis/RetainSummaryManager.h index 8ec91d741d1f..409f23caf345 100644 --- a/clang/include/clang/Analysis/RetainSummaryManager.h +++ b/clang/include/clang/Analysis/RetainSummaryManager.h @@ -203,40 +203,6 @@ public: } }; -/// 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, - ArgEffect Receiver = ArgEffect(DoNothing, ObjKind::AnyObj)) - : Ret(R), Receiver(Receiver) {} - -public: - /// Returns the argument effects for a call. - 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); -}; - /// A key identifying a summary. class ObjCSummaryKey { IdentifierInfo* II; @@ -690,9 +656,13 @@ public: bool isTrustedReferenceCountImplementation(const FunctionDecl *FD); const RetainSummary *getSummary(AnyCall C, - bool HasNonZeroCallbackArg, - bool IsReceiverUnconsumedSelf, - QualType ReceiverType=QualType()); + bool HasNonZeroCallbackArg=false, + bool IsReceiverUnconsumedSelf=false, + QualType ReceiverType={}); + + RetEffect getObjAllocRetEffect() const { return ObjCAllocRetE; } + +private: /// getMethodSummary - This version of getMethodSummary is used to query /// the summary for the current method being analyzed. @@ -700,9 +670,6 @@ public: 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, diff --git a/clang/lib/ARCMigrate/ObjCMT.cpp b/clang/lib/ARCMigrate/ObjCMT.cpp index ed891f295361..f22e03f490f4 100644 --- a/clang/lib/ARCMigrate/ObjCMT.cpp +++ b/clang/lib/ARCMigrate/ObjCMT.cpp @@ -64,9 +64,11 @@ class ObjCMigrateASTConsumer : public ASTConsumer { ObjCInstanceTypeFamily OIT_Family = OIT_None); void migrateCFAnnotation(ASTContext &Ctx, const Decl *Decl); - void AddCFAnnotations(ASTContext &Ctx, const CallEffects &CE, + void AddCFAnnotations(ASTContext &Ctx, + const RetainSummary *RS, const FunctionDecl *FuncDecl, bool ResultAnnotated); - void AddCFAnnotations(ASTContext &Ctx, const CallEffects &CE, + void AddCFAnnotations(ASTContext &Ctx, + const RetainSummary *RS, const ObjCMethodDecl *MethodDecl, bool ResultAnnotated); void AnnotateImplicitBridging(ASTContext &Ctx); @@ -84,6 +86,8 @@ class ObjCMigrateASTConsumer : public ASTConsumer { bool InsertFoundation(ASTContext &Ctx, SourceLocation Loc); + std::unique_ptr Summaries; + public: std::string MigrateDir; unsigned ASTMigrateActions; @@ -102,6 +106,14 @@ public: llvm::SmallVector CFFunctionIBCandidates; llvm::StringSet<> WhiteListFilenames; + RetainSummaryManager &getSummaryManager(ASTContext &Ctx) { + if (!Summaries) + Summaries.reset(new RetainSummaryManager(Ctx, + /*TrackNSCFObjects=*/true, + /*TrackOSObjects=*/false)); + return *Summaries; + } + ObjCMigrateASTConsumer(StringRef migrateDir, unsigned astMigrateActions, FileRemapper &remapper, @@ -1452,12 +1464,12 @@ void ObjCMigrateASTConsumer::migrateCFAnnotation(ASTContext &Ctx, const Decl *De } void ObjCMigrateASTConsumer::AddCFAnnotations(ASTContext &Ctx, - const CallEffects &CE, + const RetainSummary *RS, const FunctionDecl *FuncDecl, bool ResultAnnotated) { // Annotate function. if (!ResultAnnotated) { - RetEffect Ret = CE.getReturnValue(); + RetEffect Ret = RS->getRetEffect(); const char *AnnotationString = nullptr; if (Ret.getObjKind() == ObjKind::CF) { if (Ret.isOwned() && NSAPIObj->isMacroDefined("CF_RETURNS_RETAINED")) @@ -1477,12 +1489,11 @@ void ObjCMigrateASTConsumer::AddCFAnnotations(ASTContext &Ctx, Editor->commit(commit); } } - ArrayRef AEArgs = CE.getArgs(); unsigned i = 0; for (FunctionDecl::param_const_iterator pi = FuncDecl->param_begin(), pe = FuncDecl->param_end(); pi != pe; ++pi, ++i) { const ParmVarDecl *pd = *pi; - ArgEffect AE = AEArgs[i]; + ArgEffect AE = RS->getArg(i); if (AE.getKind() == DecRef && AE.getObjKind() == ObjKind::CF && !pd->hasAttr() && NSAPIObj->isMacroDefined("CF_CONSUMED")) { @@ -1506,7 +1517,8 @@ ObjCMigrateASTConsumer::CF_BRIDGING_KIND if (FuncDecl->hasBody()) return CF_BRIDGING_NONE; - CallEffects CE = CallEffects::getEffect(FuncDecl); + const RetainSummary *RS = + getSummaryManager(Ctx).getSummary(AnyCall(FuncDecl)); bool FuncIsReturnAnnotated = (FuncDecl->hasAttr() || FuncDecl->hasAttr() || FuncDecl->hasAttr() || @@ -1519,7 +1531,7 @@ ObjCMigrateASTConsumer::CF_BRIDGING_KIND bool ReturnCFAudited = false; if (!FuncIsReturnAnnotated) { - RetEffect Ret = CE.getReturnValue(); + RetEffect Ret = RS->getRetEffect(); if (Ret.getObjKind() == ObjKind::CF && (Ret.isOwned() || Ret.notOwned())) ReturnCFAudited = true; @@ -1528,14 +1540,12 @@ ObjCMigrateASTConsumer::CF_BRIDGING_KIND } // At this point result type is audited for potential inclusion. - // Now, how about argument types. - ArrayRef AEArgs = CE.getArgs(); unsigned i = 0; bool ArgCFAudited = false; for (FunctionDecl::param_const_iterator pi = FuncDecl->param_begin(), pe = FuncDecl->param_end(); pi != pe; ++pi, ++i) { const ParmVarDecl *pd = *pi; - ArgEffect AE = AEArgs[i]; + ArgEffect AE = RS->getArg(i); if ((AE.getKind() == DecRef /*CFConsumed annotated*/ || AE.getKind() == IncRef) && AE.getObjKind() == ObjKind::CF) { if (AE.getKind() == DecRef && !pd->hasAttr()) @@ -1545,7 +1555,7 @@ ObjCMigrateASTConsumer::CF_BRIDGING_KIND } else { QualType AT = pd->getType(); if (!AuditedType(AT)) { - AddCFAnnotations(Ctx, CE, FuncDecl, FuncIsReturnAnnotated); + AddCFAnnotations(Ctx, RS, FuncDecl, FuncIsReturnAnnotated); return CF_BRIDGING_NONE; } } @@ -1567,12 +1577,12 @@ void ObjCMigrateASTConsumer::migrateARCSafeAnnotation(ASTContext &Ctx, } void ObjCMigrateASTConsumer::AddCFAnnotations(ASTContext &Ctx, - const CallEffects &CE, + const RetainSummary *RS, const ObjCMethodDecl *MethodDecl, bool ResultAnnotated) { // Annotate function. if (!ResultAnnotated) { - RetEffect Ret = CE.getReturnValue(); + RetEffect Ret = RS->getRetEffect(); const char *AnnotationString = nullptr; if (Ret.getObjKind() == ObjKind::CF) { if (Ret.isOwned() && NSAPIObj->isMacroDefined("CF_RETURNS_RETAINED")) @@ -1604,12 +1614,11 @@ void ObjCMigrateASTConsumer::AddCFAnnotations(ASTContext &Ctx, Editor->commit(commit); } } - ArrayRef AEArgs = CE.getArgs(); unsigned i = 0; for (ObjCMethodDecl::param_const_iterator pi = MethodDecl->param_begin(), pe = MethodDecl->param_end(); pi != pe; ++pi, ++i) { const ParmVarDecl *pd = *pi; - ArgEffect AE = AEArgs[i]; + ArgEffect AE = RS->getArg(i); if (AE.getKind() == DecRef && AE.getObjKind() == ObjKind::CF && !pd->hasAttr() && @@ -1627,7 +1636,9 @@ void ObjCMigrateASTConsumer::migrateAddMethodAnnotation( if (MethodDecl->hasBody() || MethodDecl->isImplicit()) return; - CallEffects CE = CallEffects::getEffect(MethodDecl); + const RetainSummary *RS = + getSummaryManager(Ctx).getSummary(AnyCall(MethodDecl)); + bool MethodIsReturnAnnotated = (MethodDecl->hasAttr() || MethodDecl->hasAttr() || @@ -1635,7 +1646,7 @@ void ObjCMigrateASTConsumer::migrateAddMethodAnnotation( MethodDecl->hasAttr() || MethodDecl->hasAttr()); - if (CE.getReceiver().getKind() == DecRef && + if (RS->getReceiverEffect().getKind() == DecRef && !MethodDecl->hasAttr() && MethodDecl->getMethodFamily() != OMF_init && MethodDecl->getMethodFamily() != OMF_release && @@ -1651,27 +1662,25 @@ void ObjCMigrateASTConsumer::migrateAddMethodAnnotation( return; if (!MethodIsReturnAnnotated) { - RetEffect Ret = CE.getReturnValue(); + RetEffect Ret = RS->getRetEffect(); if ((Ret.getObjKind() == ObjKind::CF || Ret.getObjKind() == ObjKind::ObjC) && (Ret.isOwned() || Ret.notOwned())) { - AddCFAnnotations(Ctx, CE, MethodDecl, false); + AddCFAnnotations(Ctx, RS, MethodDecl, false); return; } else if (!AuditedType(MethodDecl->getReturnType())) return; } // At this point result type is either annotated or audited. - // Now, how about argument types. - ArrayRef AEArgs = CE.getArgs(); unsigned i = 0; for (ObjCMethodDecl::param_const_iterator pi = MethodDecl->param_begin(), pe = MethodDecl->param_end(); pi != pe; ++pi, ++i) { const ParmVarDecl *pd = *pi; - ArgEffect AE = AEArgs[i]; + ArgEffect AE = RS->getArg(i); if ((AE.getKind() == DecRef && !pd->hasAttr()) || AE.getKind() == IncRef || !AuditedType(pd->getType())) { - AddCFAnnotations(Ctx, CE, MethodDecl, MethodIsReturnAnnotated); + AddCFAnnotations(Ctx, RS, MethodDecl, MethodIsReturnAnnotated); return; } } diff --git a/clang/lib/Analysis/RetainSummaryManager.cpp b/clang/lib/Analysis/RetainSummaryManager.cpp index d8b3f818c246..96b5c9eea862 100644 --- a/clang/lib/Analysis/RetainSummaryManager.cpp +++ b/clang/lib/Analysis/RetainSummaryManager.cpp @@ -635,11 +635,14 @@ RetainSummaryManager::getSummary(AnyCall C, // FIXME: These calls are currently unsupported. return getPersistentStopSummary(); case AnyCall::ObjCMethod: { - const auto *ME = cast(C.getExpr()); - if (ME->isInstanceMessage()) + const auto *ME = cast_or_null(C.getExpr()); + if (!ME) { + return getMethodSummary(cast(C.getDecl())); + } else if (ME->isInstanceMessage()) { Summ = getInstanceMethodSummary(ME, ReceiverType); - else + } else { Summ = getClassMethodSummary(ME); + } break; } } @@ -1238,31 +1241,3 @@ RetainSummaryManager::getMethodSummary(const ObjCMethodDecl *MD) { return getMethodSummary(S, ID, MD, ResultTy, *CachedSummaries); } - -CallEffects CallEffects::getEffect(const ObjCMethodDecl *MD) { - ASTContext &Ctx = MD->getASTContext(); - RetainSummaryManager M(Ctx, - /*TrackNSAndCFObjects=*/true, - /*TrackOSObjects=*/false); - const RetainSummary *S = M.getMethodSummary(MD); - CallEffects CE(S->getRetEffect(), S->getReceiverEffect()); - unsigned N = MD->param_size(); - for (unsigned i = 0; i < N; ++i) { - CE.Args.push_back(S->getArg(i)); - } - return CE; -} - -CallEffects CallEffects::getEffect(const FunctionDecl *FD) { - ASTContext &Ctx = FD->getASTContext(); - RetainSummaryManager M(Ctx, - /*TrackNSAndCFObjects=*/true, - /*TrackOSObjects=*/false); - const RetainSummary *S = M.getFunctionSummary(FD); - CallEffects CE(S->getRetEffect()); - unsigned N = FD->param_size(); - for (unsigned i = 0; i < N; ++i) { - CE.Args.push_back(S->getArg(i)); - } - return CE; -} diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp index 1ab4106b857a..b55ea2a116e8 100644 --- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp @@ -1031,11 +1031,11 @@ ExplodedNode * RetainCountChecker::processReturn(const ReturnStmt *S, // FIXME: What is the convention for blocks? Is there one? if (const ObjCMethodDecl *MD = dyn_cast(CD)) { - const RetainSummary *Summ = Summaries.getMethodSummary(MD); + const RetainSummary *Summ = Summaries.getSummary(AnyCall(MD)); RE = Summ->getRetEffect(); } else if (const FunctionDecl *FD = dyn_cast(CD)) { if (!isa(FD)) { - const RetainSummary *Summ = Summaries.getFunctionSummary(FD); + const RetainSummary *Summ = Summaries.getSummary(AnyCall(FD)); RE = Summ->getRetEffect(); } } @@ -1324,7 +1324,7 @@ void RetainCountChecker::checkBeginFunction(CheckerContext &Ctx) const { return; ProgramStateRef state = Ctx.getState(); - const RetainSummary *FunctionSummary = SmrMgr.getFunctionSummary(FD); + const RetainSummary *FunctionSummary = SmrMgr.getSummary(AnyCall(FD)); ArgEffects CalleeSideArgEffects = FunctionSummary->getArgEffects(); for (unsigned idx = 0, e = FD->getNumParams(); idx != e; ++idx) {