24 #include "llvm/ADT/BitVector.h"
25 #include "llvm/ADT/STLExtras.h"
26 #include "llvm/ADT/SmallString.h"
27 #include "llvm/Support/SaveAndRestore.h"
29 using namespace clang;
42 return ::RecursiveASTVisitor<EHCodeVisitor>::TraverseObjCAtFinallyStmt(S);
47 return ::RecursiveASTVisitor<EHCodeVisitor>::TraverseObjCAtCatchStmt(S);
52 return TraverseStmt(S->getHandlerBlock());
70 llvm::BitVector reachable;
72 ReachableCode(
const CFG &cfg)
73 : cfg(cfg), reachable(cfg.getNumBlockIDs(),
false) {}
75 void computeReachableBlocks();
77 bool isReachable(
const CFGBlock *block)
const {
83 void ReachableCode::computeReachableBlocks() {
84 if (!cfg.getNumBlockIDs())
88 worklist.push_back(&cfg.getEntry());
90 while (!worklist.empty()) {
91 const CFGBlock *block = worklist.pop_back_val();
92 llvm::BitVector::reference isReachable = reachable[block->
getBlockID()];
99 worklist.push_back(succ);
111 if (Op == BO_Assign || Op == BO_Comma) {
121 class DeadStoresChecker :
public Checker<check::ASTCodeBody> {
123 bool ShowFixIts =
false;
124 bool WarnForDeadNestedAssignments =
true;
126 void checkASTCodeBody(
const Decl *D, AnalysisManager &Mgr,
127 BugReporter &BR)
const;
134 const DeadStoresChecker *Checker;
138 std::unique_ptr<ReachableCode> reachableCode;
140 std::unique_ptr<llvm::DenseSet<const VarDecl *>> InEH;
142 enum DeadStoreKind { Standard, Enclosing, DeadIncrement, DeadInit };
145 DeadStoreObs(
const CFG &cfg,
ASTContext &ctx, BugReporter &br,
149 bool warnForDeadNestedAssignments)
150 : cfg(cfg), Ctx(ctx), BR(br), Checker(checker), AC(ac), Parents(parents),
151 Escaped(escaped), currentBlock(nullptr) {}
153 ~DeadStoreObs()
override {}
162 EHCodeVisitor
V(*InEH.get());
169 return InEH->count(D);
186 if (Data.startswith(
"/* iig"))
192 void Report(
const VarDecl *
V, DeadStoreKind dsk,
194 if (Escaped.count(
V))
199 if (!reachableCode.get()) {
200 reachableCode.reset(
new ReachableCode(cfg));
201 reachableCode->computeReachableBlocks();
204 if (!reachableCode->isReachable(currentBlock))
211 llvm::raw_svector_ostream os(buf);
212 const char *BugType =
nullptr;
218 BugType =
"Dead initialization";
219 os <<
"Value stored to '" << *
V
220 <<
"' during its initialization is never read";
223 if (Checker->ShowFixIts) {
224 if (
V->getInit()->HasSideEffects(ACtx,
232 V->getTypeSourceInfo()->getTypeLoc().getEndLoc(),
233 SM, LO)->getEndLoc();
242 BugType =
"Dead increment";
245 if (!BugType) BugType =
"Dead assignment";
246 os <<
"Value stored to '" << *
V <<
"' is never read";
251 if (!Checker->WarnForDeadNestedAssignments)
253 BugType =
"Dead nested assignment";
254 os <<
"Although the value stored to '" << *
V
255 <<
"' is used in the enclosing expression, the value is never "
256 "actually read from '"
262 os.str(), L, R, Fixits);
276 if (!isLive(Live, VD) &&
278 VD->
hasAttr<ObjCPreciseLifetimeAttr>())) {
280 PathDiagnosticLocation ExLoc =
286 void CheckDeclRef(
const DeclRefExpr *DR,
const Expr *Val, DeadStoreKind dsk,
289 CheckVarDecl(VD, DR, Val, dsk, Live);
318 currentBlock = block;
321 if (S->getBeginLoc().isMacroID())
346 if (
const DeclRefExpr *RhsDR = dyn_cast<DeclRefExpr>(RHS))
347 if (VD == dyn_cast<VarDecl>(RhsDR->getDecl()))
353 : (isIncrement(VD,B) ? DeadIncrement : Standard);
355 CheckVarDecl(VD, DR, B->
getRHS(), dsk, Live);
359 if (!
U->isIncrementOp() ||
U->isPrefix())
363 if (!parent || !isa<ReturnStmt>(parent))
366 const Expr *Ex =
U->getSubExpr()->IgnoreParenCasts();
368 if (
const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Ex))
369 CheckDeclRef(DR,
U, DeadIncrement, Live);
371 else if (
const DeclStmt *DS = dyn_cast<DeclStmt>(S))
374 for (
const auto *DI : DS->decls()) {
375 const auto *
V = dyn_cast<VarDecl>(DI);
380 if (
V->hasLocalStorage()) {
386 if (
const Expr *E =
V->getInit()) {
387 while (
const FullExpr *FE = dyn_cast<FullExpr>(E))
388 E = FE->getSubExpr();
396 if (isa<CXXConstructExpr>(E))
402 if (!isLive(Live,
V) &&
403 !
V->hasAttr<UnusedAttr>() &&
404 !
V->hasAttr<ObjCPreciseLifetimeAttr>()) {
417 if (
const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
418 if (
const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
437 PathDiagnosticLocation Loc =
439 Report(
V, DeadInit, Loc,
V->getInit()->getSourceRange());
451 return llvm::all_of(Candidate->
inits(), [
this](
const Expr *Init) {
452 return isConstant(Init->IgnoreParenCasts());
457 bool isConstant(
const Expr *E)
const {
463 if (
const auto *ILE = dyn_cast<InitListExpr>(E)) {
464 return isConstant(ILE);
482 void operator()(
const Stmt *S) {
486 if (
auto *
LE = dyn_cast<LambdaExpr>(S)) {
487 findLambdaReferenceCaptures(
LE);
494 if (
U->getOpcode() != UO_AddrOf)
497 const Expr *E =
U->getSubExpr()->IgnoreParenCasts();
498 if (
const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E))
504 void findLambdaReferenceCaptures(
const LambdaExpr *
LE) {
506 llvm::DenseMap<const ValueDecl *, FieldDecl *> CaptureFields;
511 if (!
C.capturesVariable())
516 if (!FD || !isa<VarDecl>(VD))
521 Escaped.insert(cast<VarDecl>(VD));
532 void DeadStoresChecker::checkASTCodeBody(
const Decl *D, AnalysisManager &mgr,
533 BugReporter &BR)
const {
540 if (FD->isTemplateInstantiation())
544 CFG &cfg = *mgr.getCFG(D);
549 DeadStoreObs A(cfg, BR.getContext(), BR,
this, AC, pmap, FS.Escaped,
550 WarnForDeadNestedAssignments);
551 L->runOnAllBlocks(A);
555 void ento::registerDeadStoresChecker(CheckerManager &Mgr) {
556 auto *Chk = Mgr.registerChecker<DeadStoresChecker>();
559 Chk->WarnForDeadNestedAssignments =
562 AnOpts.getCheckerBooleanOption(Chk,
"ShowFixIts");
565 bool ento::shouldRegisterDeadStoresChecker(
const CheckerManager &mgr) {