diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp | 45 | ||||
-rw-r--r-- | clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 13 |
2 files changed, 52 insertions, 6 deletions
diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp index aa392b08608..aab5552f666 100644 --- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp @@ -1867,6 +1867,15 @@ static inline bool contains(const SmallVectorImpl<ArgEffect>& V, return false; } +static bool isNumericLiteralExpression(const Expr *E) { + // FIXME: This set of cases was copied from SemaExprObjC. + return isa<IntegerLiteral>(E) || + isa<CharacterLiteral>(E) || + isa<FloatingLiteral>(E) || + isa<ObjCBoolLiteralExpr>(E) || + isa<CXXBoolLiteralExpr>(E); +} + static bool isPropertyAccess(const Stmt *S, ParentMap &PM) { unsigned maxDepth = 4; while (S && maxDepth) { @@ -1916,6 +1925,24 @@ PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N, else if (isa<ObjCDictionaryLiteral>(S)) { os << "NSDictionary literal is an object with a +0 retain count"; } + else if (const ObjCBoxedExpr *BL = dyn_cast<ObjCBoxedExpr>(S)) { + if (isNumericLiteralExpression(BL->getSubExpr())) + os << "NSNumber literal is an object with a +0 retain count"; + else { + const ObjCInterfaceDecl *BoxClass = 0; + if (const ObjCMethodDecl *Method = BL->getBoxingMethod()) + BoxClass = Method->getClassInterface(); + + // We should always be able to find the boxing class interface, + // but consider this future-proofing. + if (BoxClass) + os << *BoxClass << " b"; + else + os << "B"; + + os << "oxed expression produces an object with a +0 retain count"; + } + } else { if (const CallExpr *CE = dyn_cast<CallExpr>(S)) { // Get the name of the callee (if it is available). @@ -2324,6 +2351,7 @@ class RetainCountChecker check::PostStmt<CXXConstructExpr>, check::PostStmt<ObjCArrayLiteral>, check::PostStmt<ObjCDictionaryLiteral>, + check::PostStmt<ObjCBoxedExpr>, check::PostObjCMessage, check::PreStmt<ReturnStmt>, check::RegionChanges, @@ -2470,6 +2498,8 @@ public: void checkPostStmt(const CXXConstructExpr *CE, CheckerContext &C) const; void checkPostStmt(const ObjCArrayLiteral *AL, CheckerContext &C) const; void checkPostStmt(const ObjCDictionaryLiteral *DL, CheckerContext &C) const; + void checkPostStmt(const ObjCBoxedExpr *BE, CheckerContext &C) const; + void checkPostObjCMessage(const ObjCMessage &Msg, CheckerContext &C) const; void checkSummary(const RetainSummary &Summ, const CallOrObjCMessage &Call, @@ -2721,6 +2751,21 @@ void RetainCountChecker::checkPostStmt(const ObjCDictionaryLiteral *DL, processObjCLiterals(C, DL); } +void RetainCountChecker::checkPostStmt(const ObjCBoxedExpr *Ex, + CheckerContext &C) const { + const ExplodedNode *Pred = C.getPredecessor(); + const LocationContext *LCtx = Pred->getLocationContext(); + ProgramStateRef State = Pred->getState(); + + if (SymbolRef Sym = State->getSVal(Ex, LCtx).getAsSymbol()) { + QualType ResultTy = Ex->getType(); + State = State->set<RefBindings>(Sym, RefVal::makeNotOwned(RetEffect::ObjC, + ResultTy)); + } + + C.addTransition(State); +} + void RetainCountChecker::checkPostObjCMessage(const ObjCMessage &Msg, CheckerContext &C) const { ProgramStateRef state = C.getState(); diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index 79d74797b3a..97a8cefd13a 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -588,7 +588,6 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::ObjCIsaExprClass: case Stmt::ObjCProtocolExprClass: case Stmt::ObjCSelectorExprClass: - case Expr::ObjCBoxedExprClass: case Stmt::ParenListExprClass: case Stmt::PredefinedExprClass: case Stmt::ShuffleVectorExprClass: @@ -628,22 +627,24 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, } case Expr::ObjCArrayLiteralClass: - case Expr::ObjCDictionaryLiteralClass: { + case Expr::ObjCDictionaryLiteralClass: + // FIXME: explicitly model with a region and the actual contents + // of the container. For now, conjure a symbol. + case Expr::ObjCBoxedExprClass: { Bldr.takeNodes(Pred); ExplodedNodeSet preVisit; getCheckerManager().runCheckersForPreStmt(preVisit, Pred, S, *this); - // FIXME: explicitly model with a region and the actual contents - // of the container. For now, conjure a symbol. ExplodedNodeSet Tmp; StmtNodeBuilder Bldr2(preVisit, Tmp, *currentBuilderContext); + const Expr *Ex = cast<Expr>(S); + QualType resultType = Ex->getType(); + for (ExplodedNodeSet::iterator it = preVisit.begin(), et = preVisit.end(); it != et; ++it) { ExplodedNode *N = *it; - const Expr *Ex = cast<Expr>(S); - QualType resultType = Ex->getType(); const LocationContext *LCtx = N->getLocationContext(); SVal result = svalBuilder.getConjuredSymbolVal(0, Ex, LCtx, resultType, |