clang  14.0.0git
AnalysisOrderChecker.cpp
Go to the documentation of this file.
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/AST/ExprCXX.h"
23 #include "llvm/Support/ErrorHandling.h"
24 
25 using namespace clang;
26 using namespace ento;
27 
28 namespace {
29 
30 class AnalysisOrderChecker
31  : public Checker<
32  check::PreStmt<CastExpr>, check::PostStmt<CastExpr>,
33  check::PreStmt<ArraySubscriptExpr>,
34  check::PostStmt<ArraySubscriptExpr>, check::PreStmt<CXXNewExpr>,
35  check::PostStmt<CXXNewExpr>, check::PreStmt<CXXDeleteExpr>,
36  check::PostStmt<CXXDeleteExpr>, check::PreStmt<CXXConstructExpr>,
37  check::PostStmt<CXXConstructExpr>, check::PreStmt<OffsetOfExpr>,
38  check::PostStmt<OffsetOfExpr>, check::PreCall, check::PostCall,
39  check::EndFunction, check::EndAnalysis, check::NewAllocator,
40  check::Bind, check::PointerEscape, check::RegionChanges,
41  check::LiveSymbols, eval::Call> {
42 
43  bool isCallbackEnabled(const AnalyzerOptions &Opts,
44  StringRef CallbackName) const {
45  return Opts.getCheckerBooleanOption(this, "*") ||
46  Opts.getCheckerBooleanOption(this, CallbackName);
47  }
48 
49  bool isCallbackEnabled(CheckerContext &C, StringRef CallbackName) const {
50  AnalyzerOptions &Opts = C.getAnalysisManager().getAnalyzerOptions();
51  return isCallbackEnabled(Opts, CallbackName);
52  }
53 
54  bool isCallbackEnabled(ProgramStateRef State, StringRef CallbackName) const {
55  AnalyzerOptions &Opts = State->getStateManager().getOwningEngine()
56  .getAnalysisManager().getAnalyzerOptions();
57  return isCallbackEnabled(Opts, CallbackName);
58  }
59 
60 public:
61  void checkPreStmt(const CastExpr *CE, CheckerContext &C) const {
62  if (isCallbackEnabled(C, "PreStmtCastExpr"))
63  llvm::errs() << "PreStmt<CastExpr> (Kind : " << CE->getCastKindName()
64  << ")\n";
65  }
66 
67  void checkPostStmt(const CastExpr *CE, CheckerContext &C) const {
68  if (isCallbackEnabled(C, "PostStmtCastExpr"))
69  llvm::errs() << "PostStmt<CastExpr> (Kind : " << CE->getCastKindName()
70  << ")\n";
71  }
72 
73  void checkPreStmt(const ArraySubscriptExpr *SubExpr,
74  CheckerContext &C) const {
75  if (isCallbackEnabled(C, "PreStmtArraySubscriptExpr"))
76  llvm::errs() << "PreStmt<ArraySubscriptExpr>\n";
77  }
78 
79  void checkPostStmt(const ArraySubscriptExpr *SubExpr,
80  CheckerContext &C) const {
81  if (isCallbackEnabled(C, "PostStmtArraySubscriptExpr"))
82  llvm::errs() << "PostStmt<ArraySubscriptExpr>\n";
83  }
84 
85  void checkPreStmt(const CXXNewExpr *NE, CheckerContext &C) const {
86  if (isCallbackEnabled(C, "PreStmtCXXNewExpr"))
87  llvm::errs() << "PreStmt<CXXNewExpr>\n";
88  }
89 
90  void checkPostStmt(const CXXNewExpr *NE, CheckerContext &C) const {
91  if (isCallbackEnabled(C, "PostStmtCXXNewExpr"))
92  llvm::errs() << "PostStmt<CXXNewExpr>\n";
93  }
94 
95  void checkPreStmt(const CXXDeleteExpr *NE, CheckerContext &C) const {
96  if (isCallbackEnabled(C, "PreStmtCXXDeleteExpr"))
97  llvm::errs() << "PreStmt<CXXDeleteExpr>\n";
98  }
99 
100  void checkPostStmt(const CXXDeleteExpr *NE, CheckerContext &C) const {
101  if (isCallbackEnabled(C, "PostStmtCXXDeleteExpr"))
102  llvm::errs() << "PostStmt<CXXDeleteExpr>\n";
103  }
104 
105  void checkPreStmt(const CXXConstructExpr *NE, CheckerContext &C) const {
106  if (isCallbackEnabled(C, "PreStmtCXXConstructExpr"))
107  llvm::errs() << "PreStmt<CXXConstructExpr>\n";
108  }
109 
110  void checkPostStmt(const CXXConstructExpr *NE, CheckerContext &C) const {
111  if (isCallbackEnabled(C, "PostStmtCXXConstructExpr"))
112  llvm::errs() << "PostStmt<CXXConstructExpr>\n";
113  }
114 
115  void checkPreStmt(const OffsetOfExpr *OOE, CheckerContext &C) const {
116  if (isCallbackEnabled(C, "PreStmtOffsetOfExpr"))
117  llvm::errs() << "PreStmt<OffsetOfExpr>\n";
118  }
119 
120  void checkPostStmt(const OffsetOfExpr *OOE, CheckerContext &C) const {
121  if (isCallbackEnabled(C, "PostStmtOffsetOfExpr"))
122  llvm::errs() << "PostStmt<OffsetOfExpr>\n";
123  }
124 
125  bool evalCall(const CallEvent &Call, CheckerContext &C) const {
126  if (isCallbackEnabled(C, "EvalCall")) {
127  llvm::errs() << "EvalCall";
128  if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Call.getDecl()))
129  llvm::errs() << " (" << ND->getQualifiedNameAsString() << ')';
130  llvm::errs() << " {argno: " << Call.getNumArgs() << '}';
131  llvm::errs() << " [" << Call.getKindAsString() << ']';
132  llvm::errs() << '\n';
133  return true;
134  }
135  return false;
136  }
137 
138  void checkPreCall(const CallEvent &Call, CheckerContext &C) const {
139  if (isCallbackEnabled(C, "PreCall")) {
140  llvm::errs() << "PreCall";
141  if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Call.getDecl()))
142  llvm::errs() << " (" << ND->getQualifiedNameAsString() << ')';
143  llvm::errs() << " [" << Call.getKindAsString() << ']';
144  llvm::errs() << '\n';
145  }
146  }
147 
148  void checkPostCall(const CallEvent &Call, CheckerContext &C) const {
149  if (isCallbackEnabled(C, "PostCall")) {
150  llvm::errs() << "PostCall";
151  if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Call.getDecl()))
152  llvm::errs() << " (" << ND->getQualifiedNameAsString() << ')';
153  llvm::errs() << " [" << Call.getKindAsString() << ']';
154  llvm::errs() << '\n';
155  }
156  }
157 
158  void checkEndFunction(const ReturnStmt *S, CheckerContext &C) const {
159  if (isCallbackEnabled(C, "EndFunction")) {
160  llvm::errs() << "EndFunction\nReturnStmt: " << (S ? "yes" : "no") << "\n";
161  if (!S)
162  return;
163 
164  llvm::errs() << "CFGElement: ";
165  CFGStmtMap *Map = C.getCurrentAnalysisDeclContext()->getCFGStmtMap();
166  CFGElement LastElement = Map->getBlock(S)->back();
167 
168  if (LastElement.getAs<CFGStmt>())
169  llvm::errs() << "CFGStmt\n";
170  else if (LastElement.getAs<CFGAutomaticObjDtor>())
171  llvm::errs() << "CFGAutomaticObjDtor\n";
172  }
173  }
174 
175  void checkEndAnalysis(ExplodedGraph &G, BugReporter &BR,
176  ExprEngine &Eng) const {
177  if (isCallbackEnabled(BR.getAnalyzerOptions(), "EndAnalysis"))
178  llvm::errs() << "EndAnalysis\n";
179  }
180 
181  void checkNewAllocator(const CXXAllocatorCall &Call,
182  CheckerContext &C) const {
183  if (isCallbackEnabled(C, "NewAllocator"))
184  llvm::errs() << "NewAllocator\n";
185  }
186 
187  void checkBind(SVal Loc, SVal Val, const Stmt *S, CheckerContext &C) const {
188  if (isCallbackEnabled(C, "Bind"))
189  llvm::errs() << "Bind\n";
190  }
191 
192  void checkLiveSymbols(ProgramStateRef State, SymbolReaper &SymReaper) const {
193  if (isCallbackEnabled(State, "LiveSymbols"))
194  llvm::errs() << "LiveSymbols\n";
195  }
196 
198  checkRegionChanges(ProgramStateRef State,
199  const InvalidatedSymbols *Invalidated,
200  ArrayRef<const MemRegion *> ExplicitRegions,
202  const LocationContext *LCtx, const CallEvent *Call) const {
203  if (isCallbackEnabled(State, "RegionChanges"))
204  llvm::errs() << "RegionChanges\n";
205  return State;
206  }
207 
208  ProgramStateRef checkPointerEscape(ProgramStateRef State,
209  const InvalidatedSymbols &Escaped,
210  const CallEvent *Call,
211  PointerEscapeKind Kind) const {
212  if (isCallbackEnabled(State, "PointerEscape"))
213  llvm::errs() << "PointerEscape\n";
214  return State;
215  }
216 };
217 } // end anonymous namespace
218 
219 //===----------------------------------------------------------------------===//
220 // Registration.
221 //===----------------------------------------------------------------------===//
222 
223 void ento::registerAnalysisOrderChecker(CheckerManager &mgr) {
224  mgr.registerChecker<AnalysisOrderChecker>();
225 }
226 
227 bool ento::shouldRegisterAnalysisOrderChecker(const CheckerManager &mgr) {
228  return true;
229 }
clang::OffsetOfExpr
OffsetOfExpr - [C99 7.17] - This represents an expression of the form offsetof(record-type,...
Definition: Expr.h:2438
clang::LocationContext
It wraps the AnalysisDeclContext to represent both the call stack with the help of StackFrameContext ...
Definition: AnalysisDeclContext.h:215
clang::NamedDecl
This represents a decl that may have a name.
Definition: Decl.h:249
clang::ento::ProgramStateRef
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
Definition: ProgramState_Fwd.h:37
AttributeLangSupport::C
@ C
Definition: SemaDeclAttr.cpp:54
clang::CXXNewExpr
Represents a new-expression for memory allocation and constructor calls, e.g: "new CXXNewExpr(foo)".
Definition: ExprCXX.h:2139
clang::index::SymbolRole::Call
@ Call
CallEvent.h
BuiltinCheckerRegistration.h
CheckerManager.h
clang::CFGAutomaticObjDtor
Represents C++ object destructor implicitly generated for automatic object or temporary bound to cons...
Definition: CFG.h:389
clang::CFGStmtMap::getBlock
CFGBlock * getBlock(Stmt *S)
Returns the CFGBlock the specified Stmt* appears in.
Definition: CFGStmtMap.cpp:26
ExprCXX.h
clang::CFGStmtMap
Definition: CFGStmtMap.h:24
CFGStmtMap.h
clang::CFGBlock::back
CFGElement back() const
Definition: CFG.h:873
clang::CFGStmt
Definition: CFG.h:132
clang::CFGElement::getAs
Optional< T > getAs() const
Convert to the specified CFGElement type, returning None if this CFGElement is not of the desired typ...
Definition: CFG.h:109
clang::CXXDeleteExpr
Represents a delete expression for memory deallocation and destructor calls, e.g.
Definition: ExprCXX.h:2398
llvm::ArrayRef
Definition: LLVM.h:34
clang::ArraySubscriptExpr
ArraySubscriptExpr - [C99 6.5.2.1] Array Subscripting.
Definition: Expr.h:2639
clang::AnalyzerOptions
Stores options for the analyzer from the command line.
Definition: AnalyzerOptions.h:163
State
LineState State
Definition: UnwrappedLineFormatter.cpp:986
CheckerContext.h
clang::CFGElement
Represents a top-level expression in a basic block.
Definition: CFG.h:55
clang::ObjCPropertyAttribute::Kind
Kind
Definition: DeclObjCCommon.h:22
clang::AnalyzerOptions::getCheckerBooleanOption
bool getCheckerBooleanOption(StringRef CheckerName, StringRef OptionName, bool SearchInParents=false) const
Interprets an option's string value as a boolean.
Definition: AnalyzerOptions.cpp:151
Checker.h
clang::interp::NE
bool NE(InterpState &S, CodePtr OpPC)
Definition: Interp.h:225
clang
Definition: CalledOnceCheck.h:17
clang::Stmt
Stmt - This represents one statement.
Definition: Stmt.h:69
clang::ento::PointerEscapeKind
PointerEscapeKind
Describes the different reasons a pointer escapes during analysis.
Definition: CheckerManager.h:79
clang::ento::InvalidatedSymbols
llvm::DenseSet< SymbolRef > InvalidatedSymbols
Definition: Store.h:51
clang::CastExpr::getCastKindName
static const char * getCastKindName(CastKind CK)
Definition: Expr.cpp:1877
clang::CastExpr
CastExpr - Base class for type casts, including both implicit casts (ImplicitCastExpr) and explicit c...
Definition: Expr.h:3473
clang::CXXConstructExpr
Represents a call to a C++ constructor.
Definition: ExprCXX.h:1460
clang::ReturnStmt
ReturnStmt - This represents a return, optionally of an expression: return; return 4;.
Definition: Stmt.h:2760