AnalysisOrderChecker.cpp revision 360784
1//===- AnalysisOrderChecker - Print callbacks called ------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This checker prints callbacks that are called during analysis.
10// This is required to ensure that callbacks are fired in order
11// and do not duplicate or get lost.
12// Feel free to extend this checker with any callback you need to check.
13//
14//===----------------------------------------------------------------------===//
15
16#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
17#include "clang/AST/ExprCXX.h"
18#include "clang/Analysis/CFGStmtMap.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
24using namespace clang;
25using namespace ento;
26
27namespace {
28
29class 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::EndFunction,
41                     check::NewAllocator,
42                     check::Bind,
43                     check::PointerEscape,
44                     check::RegionChanges,
45                     check::LiveSymbols> {
46
47  bool isCallbackEnabled(AnalyzerOptions &Opts, StringRef CallbackName) const {
48    return Opts.getCheckerBooleanOption(this, "*") ||
49           Opts.getCheckerBooleanOption(this, CallbackName);
50  }
51
52  bool isCallbackEnabled(CheckerContext &C, StringRef CallbackName) const {
53    AnalyzerOptions &Opts = C.getAnalysisManager().getAnalyzerOptions();
54    return isCallbackEnabled(Opts, CallbackName);
55  }
56
57  bool isCallbackEnabled(ProgramStateRef State, StringRef CallbackName) const {
58    AnalyzerOptions &Opts = State->getStateManager().getOwningEngine()
59                                 .getAnalysisManager().getAnalyzerOptions();
60    return isCallbackEnabled(Opts, CallbackName);
61  }
62
63public:
64  void checkPreStmt(const CastExpr *CE, CheckerContext &C) const {
65    if (isCallbackEnabled(C, "PreStmtCastExpr"))
66      llvm::errs() << "PreStmt<CastExpr> (Kind : " << CE->getCastKindName()
67                   << ")\n";
68  }
69
70  void checkPostStmt(const CastExpr *CE, CheckerContext &C) const {
71    if (isCallbackEnabled(C, "PostStmtCastExpr"))
72      llvm::errs() << "PostStmt<CastExpr> (Kind : " << CE->getCastKindName()
73                   << ")\n";
74  }
75
76  void checkPreStmt(const ArraySubscriptExpr *SubExpr,
77                    CheckerContext &C) const {
78    if (isCallbackEnabled(C, "PreStmtArraySubscriptExpr"))
79      llvm::errs() << "PreStmt<ArraySubscriptExpr>\n";
80  }
81
82  void checkPostStmt(const ArraySubscriptExpr *SubExpr,
83                     CheckerContext &C) const {
84    if (isCallbackEnabled(C, "PostStmtArraySubscriptExpr"))
85      llvm::errs() << "PostStmt<ArraySubscriptExpr>\n";
86  }
87
88  void checkPreStmt(const CXXNewExpr *NE, CheckerContext &C) const {
89    if (isCallbackEnabled(C, "PreStmtCXXNewExpr"))
90      llvm::errs() << "PreStmt<CXXNewExpr>\n";
91  }
92
93  void checkPostStmt(const CXXNewExpr *NE, CheckerContext &C) const {
94    if (isCallbackEnabled(C, "PostStmtCXXNewExpr"))
95      llvm::errs() << "PostStmt<CXXNewExpr>\n";
96  }
97
98  void checkPreStmt(const OffsetOfExpr *OOE, CheckerContext &C) const {
99    if (isCallbackEnabled(C, "PreStmtOffsetOfExpr"))
100      llvm::errs() << "PreStmt<OffsetOfExpr>\n";
101  }
102
103  void checkPostStmt(const OffsetOfExpr *OOE, CheckerContext &C) const {
104    if (isCallbackEnabled(C, "PostStmtOffsetOfExpr"))
105      llvm::errs() << "PostStmt<OffsetOfExpr>\n";
106  }
107
108  void checkPreCall(const CallEvent &Call, CheckerContext &C) const {
109    if (isCallbackEnabled(C, "PreCall")) {
110      llvm::errs() << "PreCall";
111      if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Call.getDecl()))
112        llvm::errs() << " (" << ND->getQualifiedNameAsString() << ')';
113      llvm::errs() << '\n';
114    }
115  }
116
117  void checkPostCall(const CallEvent &Call, CheckerContext &C) const {
118    if (isCallbackEnabled(C, "PostCall")) {
119      llvm::errs() << "PostCall";
120      if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Call.getDecl()))
121        llvm::errs() << " (" << ND->getQualifiedNameAsString() << ')';
122      llvm::errs() << '\n';
123    }
124  }
125
126  void checkEndFunction(const ReturnStmt *S, CheckerContext &C) const {
127    if (isCallbackEnabled(C, "EndFunction")) {
128      llvm::errs() << "EndFunction\nReturnStmt: " << (S ? "yes" : "no") << "\n";
129      if (!S)
130        return;
131
132      llvm::errs() << "CFGElement: ";
133      CFGStmtMap *Map = C.getCurrentAnalysisDeclContext()->getCFGStmtMap();
134      CFGElement LastElement = Map->getBlock(S)->back();
135
136      if (LastElement.getAs<CFGStmt>())
137        llvm::errs() << "CFGStmt\n";
138      else if (LastElement.getAs<CFGAutomaticObjDtor>())
139        llvm::errs() << "CFGAutomaticObjDtor\n";
140    }
141  }
142
143  void checkNewAllocator(const CXXNewExpr *CNE, SVal Target,
144                         CheckerContext &C) const {
145    if (isCallbackEnabled(C, "NewAllocator"))
146      llvm::errs() << "NewAllocator\n";
147  }
148
149  void checkBind(SVal Loc, SVal Val, const Stmt *S, CheckerContext &C) const {
150    if (isCallbackEnabled(C, "Bind"))
151      llvm::errs() << "Bind\n";
152  }
153
154  void checkLiveSymbols(ProgramStateRef State, SymbolReaper &SymReaper) const {
155    if (isCallbackEnabled(State, "LiveSymbols"))
156      llvm::errs() << "LiveSymbols\n";
157  }
158
159  ProgramStateRef
160  checkRegionChanges(ProgramStateRef State,
161                     const InvalidatedSymbols *Invalidated,
162                     ArrayRef<const MemRegion *> ExplicitRegions,
163                     ArrayRef<const MemRegion *> Regions,
164                     const LocationContext *LCtx, const CallEvent *Call) const {
165    if (isCallbackEnabled(State, "RegionChanges"))
166      llvm::errs() << "RegionChanges\n";
167    return State;
168  }
169
170  ProgramStateRef checkPointerEscape(ProgramStateRef State,
171                                     const InvalidatedSymbols &Escaped,
172                                     const CallEvent *Call,
173                                     PointerEscapeKind Kind) const {
174    if (isCallbackEnabled(State, "PointerEscape"))
175      llvm::errs() << "PointerEscape\n";
176    return State;
177  }
178};
179} // end anonymous namespace
180
181//===----------------------------------------------------------------------===//
182// Registration.
183//===----------------------------------------------------------------------===//
184
185void ento::registerAnalysisOrderChecker(CheckerManager &mgr) {
186  mgr.registerChecker<AnalysisOrderChecker>();
187}
188
189bool ento::shouldRegisterAnalysisOrderChecker(const LangOptions &LO) {
190  return true;
191}
192