1 //===- AnalysisOrderChecker - Print callbacks called ------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This checker prints callbacks that are called during analysis. 11 // This is required to ensure that callbacks are fired in order 12 // and do not duplicate or get lost. 13 // Feel free to extend this checker with any callback you need to check. 14 // 15 //===----------------------------------------------------------------------===// 16 17 #include "ClangSACheckers.h" 18 #include "clang/AST/ExprCXX.h" 19 #include "clang/StaticAnalyzer/Core/Checker.h" 20 #include "clang/StaticAnalyzer/Core/CheckerManager.h" 21 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" 22 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 23 24 using namespace clang; 25 using namespace ento; 26 27 namespace { 28 29 class AnalysisOrderChecker 30 : public Checker<check::PreStmt<CastExpr>, 31 check::PostStmt<CastExpr>, 32 check::PreStmt<ArraySubscriptExpr>, 33 check::PostStmt<ArraySubscriptExpr>, 34 check::PreStmt<CXXNewExpr>, 35 check::PostStmt<CXXNewExpr>, 36 check::PreStmt<OffsetOfExpr>, 37 check::PostStmt<OffsetOfExpr>, 38 check::PreCall, 39 check::PostCall, 40 check::NewAllocator, 41 check::Bind, 42 check::RegionChanges, 43 check::LiveSymbols> { 44 45 bool isCallbackEnabled(AnalyzerOptions &Opts, StringRef CallbackName) const { 46 return Opts.getBooleanOption("*", false, this) || 47 Opts.getBooleanOption(CallbackName, false, this); 48 } 49 50 bool isCallbackEnabled(CheckerContext &C, StringRef CallbackName) const { 51 AnalyzerOptions &Opts = C.getAnalysisManager().getAnalyzerOptions(); 52 return isCallbackEnabled(Opts, CallbackName); 53 } 54 55 bool isCallbackEnabled(ProgramStateRef State, StringRef CallbackName) const { 56 AnalyzerOptions &Opts = State->getStateManager().getOwningEngine() 57 ->getAnalysisManager().getAnalyzerOptions(); 58 return isCallbackEnabled(Opts, CallbackName); 59 } 60 61 public: 62 void checkPreStmt(const CastExpr *CE, CheckerContext &C) const { 63 if (isCallbackEnabled(C, "PreStmtCastExpr")) 64 llvm::errs() << "PreStmt<CastExpr> (Kind : " << CE->getCastKindName() 65 << ")\n"; 66 } 67 68 void checkPostStmt(const CastExpr *CE, CheckerContext &C) const { 69 if (isCallbackEnabled(C, "PostStmtCastExpr")) 70 llvm::errs() << "PostStmt<CastExpr> (Kind : " << CE->getCastKindName() 71 << ")\n"; 72 } 73 74 void checkPreStmt(const ArraySubscriptExpr *SubExpr, 75 CheckerContext &C) const { 76 if (isCallbackEnabled(C, "PreStmtArraySubscriptExpr")) 77 llvm::errs() << "PreStmt<ArraySubscriptExpr>\n"; 78 } 79 80 void checkPostStmt(const ArraySubscriptExpr *SubExpr, 81 CheckerContext &C) const { 82 if (isCallbackEnabled(C, "PostStmtArraySubscriptExpr")) 83 llvm::errs() << "PostStmt<ArraySubscriptExpr>\n"; 84 } 85 86 void checkPreStmt(const CXXNewExpr *NE, CheckerContext &C) const { 87 if (isCallbackEnabled(C, "PreStmtCXXNewExpr")) 88 llvm::errs() << "PreStmt<CXXNewExpr>\n"; 89 } 90 91 void checkPostStmt(const CXXNewExpr *NE, CheckerContext &C) const { 92 if (isCallbackEnabled(C, "PostStmtCXXNewExpr")) 93 llvm::errs() << "PostStmt<CXXNewExpr>\n"; 94 } 95 96 void checkPreStmt(const OffsetOfExpr *OOE, CheckerContext &C) const { 97 if (isCallbackEnabled(C, "PreStmtOffsetOfExpr")) 98 llvm::errs() << "PreStmt<OffsetOfExpr>\n"; 99 } 100 101 void checkPostStmt(const OffsetOfExpr *OOE, CheckerContext &C) const { 102 if (isCallbackEnabled(C, "PostStmtOffsetOfExpr")) 103 llvm::errs() << "PostStmt<OffsetOfExpr>\n"; 104 } 105 106 void checkPreCall(const CallEvent &Call, CheckerContext &C) const { 107 if (isCallbackEnabled(C, "PreCall")) { 108 llvm::errs() << "PreCall"; 109 if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Call.getDecl())) 110 llvm::errs() << " (" << ND->getQualifiedNameAsString() << ')'; 111 llvm::errs() << '\n'; 112 } 113 } 114 115 void checkPostCall(const CallEvent &Call, CheckerContext &C) const { 116 if (isCallbackEnabled(C, "PostCall")) { 117 llvm::errs() << "PostCall"; 118 if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Call.getDecl())) 119 llvm::errs() << " (" << ND->getQualifiedNameAsString() << ')'; 120 llvm::errs() << '\n'; 121 } 122 } 123 124 void checkNewAllocator(const CXXNewExpr *CNE, SVal Target, 125 CheckerContext &C) const { 126 if (isCallbackEnabled(C, "NewAllocator")) 127 llvm::errs() << "NewAllocator\n"; 128 } 129 130 void checkBind(SVal Loc, SVal Val, const Stmt *S, CheckerContext &C) const { 131 if (isCallbackEnabled(C, "Bind")) 132 llvm::errs() << "Bind\n"; 133 } 134 135 void checkLiveSymbols(ProgramStateRef State, SymbolReaper &SymReaper) const { 136 if (isCallbackEnabled(State, "LiveSymbols")) 137 llvm::errs() << "LiveSymbols\n"; 138 } 139 140 ProgramStateRef 141 checkRegionChanges(ProgramStateRef State, 142 const InvalidatedSymbols *Invalidated, 143 ArrayRef<const MemRegion *> ExplicitRegions, 144 ArrayRef<const MemRegion *> Regions, 145 const LocationContext *LCtx, const CallEvent *Call) const { 146 if (isCallbackEnabled(State, "RegionChanges")) 147 llvm::errs() << "RegionChanges\n"; 148 return State; 149 } 150 }; 151 } // end anonymous namespace 152 153 //===----------------------------------------------------------------------===// 154 // Registration. 155 //===----------------------------------------------------------------------===// 156 157 void ento::registerAnalysisOrderChecker(CheckerManager &mgr) { 158 mgr.registerChecker<AnalysisOrderChecker>(); 159 } 160