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::PreCall,
37                      check::PostCall,
38                      check::NewAllocator,
39                      check::Bind,
40                      check::RegionChanges,
41                      check::LiveSymbols> {
42 
43   bool isCallbackEnabled(AnalyzerOptions &Opts, StringRef CallbackName) const {
44     return Opts.getBooleanOption("*", false, this) ||
45         Opts.getBooleanOption(CallbackName, false, this);
46   }
47 
48   bool isCallbackEnabled(CheckerContext &C, StringRef CallbackName) const {
49     AnalyzerOptions &Opts = C.getAnalysisManager().getAnalyzerOptions();
50     return isCallbackEnabled(Opts, CallbackName);
51   }
52 
53   bool isCallbackEnabled(ProgramStateRef State, StringRef CallbackName) const {
54     AnalyzerOptions &Opts = State->getStateManager().getOwningEngine()
55                                  ->getAnalysisManager().getAnalyzerOptions();
56     return isCallbackEnabled(Opts, CallbackName);
57   }
58 
59 public:
60   void checkPreStmt(const CastExpr *CE, CheckerContext &C) const {
61     if (isCallbackEnabled(C, "PreStmtCastExpr"))
62       llvm::errs() << "PreStmt<CastExpr> (Kind : " << CE->getCastKindName()
63                    << ")\n";
64   }
65 
66   void checkPostStmt(const CastExpr *CE, CheckerContext &C) const {
67     if (isCallbackEnabled(C, "PostStmtCastExpr"))
68       llvm::errs() << "PostStmt<CastExpr> (Kind : " << CE->getCastKindName()
69                    << ")\n";
70   }
71 
72   void checkPreStmt(const ArraySubscriptExpr *SubExpr,
73                     CheckerContext &C) const {
74     if (isCallbackEnabled(C, "PreStmtArraySubscriptExpr"))
75       llvm::errs() << "PreStmt<ArraySubscriptExpr>\n";
76   }
77 
78   void checkPostStmt(const ArraySubscriptExpr *SubExpr,
79                      CheckerContext &C) const {
80     if (isCallbackEnabled(C, "PostStmtArraySubscriptExpr"))
81       llvm::errs() << "PostStmt<ArraySubscriptExpr>\n";
82   }
83 
84   void checkPreStmt(const CXXNewExpr *NE, CheckerContext &C) const {
85     if (isCallbackEnabled(C, "PreStmtCXXNewExpr"))
86       llvm::errs() << "PreStmt<CXXNewExpr>\n";
87   }
88 
89   void checkPostStmt(const CXXNewExpr *NE, CheckerContext &C) const {
90     if (isCallbackEnabled(C, "PostStmtCXXNewExpr"))
91       llvm::errs() << "PostStmt<CXXNewExpr>\n";
92   }
93 
94   void checkPreCall(const CallEvent &Call, CheckerContext &C) const {
95     if (isCallbackEnabled(C, "PreCall")) {
96       llvm::errs() << "PreCall";
97       if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Call.getDecl()))
98         llvm::errs() << " (" << ND->getQualifiedNameAsString() << ')';
99       llvm::errs() << '\n';
100     }
101   }
102 
103   void checkPostCall(const CallEvent &Call, CheckerContext &C) const {
104     if (isCallbackEnabled(C, "PostCall")) {
105       llvm::errs() << "PostCall";
106       if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Call.getDecl()))
107         llvm::errs() << " (" << ND->getQualifiedNameAsString() << ')';
108       llvm::errs() << '\n';
109     }
110   }
111 
112   void checkNewAllocator(const CXXNewExpr *CNE, SVal Target,
113                          CheckerContext &C) const {
114     if (isCallbackEnabled(C, "NewAllocator"))
115       llvm::errs() << "NewAllocator\n";
116   }
117 
118   void checkBind(SVal Loc, SVal Val, const Stmt *S, CheckerContext &C) const {
119     if (isCallbackEnabled(C, "Bind"))
120       llvm::errs() << "Bind\n";
121   }
122 
123   void checkLiveSymbols(ProgramStateRef State, SymbolReaper &SymReaper) const {
124     if (isCallbackEnabled(State, "LiveSymbols"))
125       llvm::errs() << "LiveSymbols\n";
126   }
127 
128   ProgramStateRef
129   checkRegionChanges(ProgramStateRef State,
130                      const InvalidatedSymbols *Invalidated,
131                      ArrayRef<const MemRegion *> ExplicitRegions,
132                      ArrayRef<const MemRegion *> Regions,
133                      const LocationContext *LCtx, const CallEvent *Call) const {
134     if (isCallbackEnabled(State, "RegionChanges"))
135       llvm::errs() << "RegionChanges\n";
136     return State;
137   }
138 };
139 } // end anonymous namespace
140 
141 //===----------------------------------------------------------------------===//
142 // Registration.
143 //===----------------------------------------------------------------------===//
144 
145 void ento::registerAnalysisOrderChecker(CheckerManager &mgr) {
146   mgr.registerChecker<AnalysisOrderChecker>();
147 }
148