//==- DeadStores.cpp - Check for stores to dead variables --------*- C++ -*-==// // // The LLVM Compiler Infrastructure // // This file was developed by Ted Kremenek and is distributed under // the University of Illinois Open Source License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This files defines a DeadStores, a flow-sensitive checker that looks for // stores to variables that are no longer live. // //===----------------------------------------------------------------------===// #include "clang/AST/Expr.h" #include "clang/Analysis/LocalCheckers.h" #include "clang/Analysis/LiveVariables.h" #include "clang/AST/CFG.h" #include "clang/Basic/Diagnostic.h" #include "clang/AST/ASTContext.h" using namespace clang; namespace { class DeadStoreObserver : public LiveVariablesObserver { ASTContext &Ctx; Diagnostic &Diags; public: DeadStoreObserver(ASTContext &ctx, Diagnostic &diags) : Ctx(ctx), Diags(diags) { } virtual ~DeadStoreObserver() {} virtual void ObserveStmt(Stmt* S, LiveVariables& L, llvm::BitVector& Live) { if (BinaryOperator* B = dyn_cast(S)) { // Is this an assignment? if (!B->isAssignmentOp()) return; // Is this an assignment to a variable? if (DeclRefExpr* DR = dyn_cast(B->getLHS())) // Is the variable live? if (!L.isLive(Live,cast(DR->getDecl()))) { SourceRange R = B->getRHS()->getSourceRange(); Diags.Report(DR->getSourceRange().Begin(), diag::warn_dead_store, 0, 0, &R, 1); } } else if(DeclStmt* DS = dyn_cast(S)) { // Iterate through the decls. Warn if any of them (which have // initializers) are not live. for (VarDecl* V = cast(DS->getDecl()); V != NULL ; V = cast_or_null(V->getNextDeclarator())) if (Expr* E = V->getInit()) if (!L.isLive(Live,V)) // Special case: check for initializations with constants. // // e.g. : int x = 0; // // If x is EVER assigned a new value later, don't issue // a warning. This is because such initialization can be // due to defensive programming. if (!E->isConstantExpr(Ctx,NULL) || L.getVarInfo(V).Kills.size() == 0) { // Flag a warning. SourceRange R = E->getSourceRange(); Diags.Report(V->getLocation(), diag::warn_dead_store, 0, 0, &R,1); } } } }; } // end anonymous namespace namespace clang { void CheckDeadStores(CFG& cfg, LiveVariables& L, ASTContext &Ctx, Diagnostic &Diags) { DeadStoreObserver A(Ctx, Diags); for (CFG::iterator I = cfg.begin(), E = cfg.end(); I != E; ++I) L.runOnBlock(&(*I),&A); } void CheckDeadStores(CFG& cfg, ASTContext &Ctx, Diagnostic &Diags) { LiveVariables L; L.runOnCFG(cfg); CheckDeadStores(cfg,L, Ctx, Diags); } } // end namespace clang