1311118Sdim//===- AnalysisOrderChecker - Print callbacks called ------------*- C++ -*-===//
2311118Sdim//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6311118Sdim//
7311118Sdim//===----------------------------------------------------------------------===//
8311118Sdim//
9311118Sdim// This checker prints callbacks that are called during analysis.
10311118Sdim// This is required to ensure that callbacks are fired in order
11311118Sdim// and do not duplicate or get lost.
12311118Sdim// Feel free to extend this checker with any callback you need to check.
13311118Sdim//
14311118Sdim//===----------------------------------------------------------------------===//
15311118Sdim
16344779Sdim#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
17341825Sdim#include "clang/AST/ExprCXX.h"
18344779Sdim#include "clang/Analysis/CFGStmtMap.h"
19311118Sdim#include "clang/StaticAnalyzer/Core/Checker.h"
20311118Sdim#include "clang/StaticAnalyzer/Core/CheckerManager.h"
21341825Sdim#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
22311118Sdim#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
23311118Sdim
24311118Sdimusing namespace clang;
25311118Sdimusing namespace ento;
26311118Sdim
27311118Sdimnamespace {
28311118Sdim
29321369Sdimclass AnalysisOrderChecker
30321369Sdim    : public Checker<check::PreStmt<CastExpr>,
31321369Sdim                     check::PostStmt<CastExpr>,
32321369Sdim                     check::PreStmt<ArraySubscriptExpr>,
33321369Sdim                     check::PostStmt<ArraySubscriptExpr>,
34341825Sdim                     check::PreStmt<CXXNewExpr>,
35341825Sdim                     check::PostStmt<CXXNewExpr>,
36341825Sdim                     check::PreStmt<OffsetOfExpr>,
37341825Sdim                     check::PostStmt<OffsetOfExpr>,
38341825Sdim                     check::PreCall,
39341825Sdim                     check::PostCall,
40344779Sdim                     check::EndFunction,
41341825Sdim                     check::NewAllocator,
42321369Sdim                     check::Bind,
43360784Sdim                     check::PointerEscape,
44341825Sdim                     check::RegionChanges,
45341825Sdim                     check::LiveSymbols> {
46341825Sdim
47321369Sdim  bool isCallbackEnabled(AnalyzerOptions &Opts, StringRef CallbackName) const {
48353358Sdim    return Opts.getCheckerBooleanOption(this, "*") ||
49353358Sdim           Opts.getCheckerBooleanOption(this, CallbackName);
50311118Sdim  }
51311118Sdim
52321369Sdim  bool isCallbackEnabled(CheckerContext &C, StringRef CallbackName) const {
53321369Sdim    AnalyzerOptions &Opts = C.getAnalysisManager().getAnalyzerOptions();
54321369Sdim    return isCallbackEnabled(Opts, CallbackName);
55321369Sdim  }
56321369Sdim
57321369Sdim  bool isCallbackEnabled(ProgramStateRef State, StringRef CallbackName) const {
58321369Sdim    AnalyzerOptions &Opts = State->getStateManager().getOwningEngine()
59344779Sdim                                 .getAnalysisManager().getAnalyzerOptions();
60321369Sdim    return isCallbackEnabled(Opts, CallbackName);
61321369Sdim  }
62321369Sdim
63311118Sdimpublic:
64311118Sdim  void checkPreStmt(const CastExpr *CE, CheckerContext &C) const {
65311118Sdim    if (isCallbackEnabled(C, "PreStmtCastExpr"))
66311118Sdim      llvm::errs() << "PreStmt<CastExpr> (Kind : " << CE->getCastKindName()
67311118Sdim                   << ")\n";
68311118Sdim  }
69311118Sdim
70311118Sdim  void checkPostStmt(const CastExpr *CE, CheckerContext &C) const {
71311118Sdim    if (isCallbackEnabled(C, "PostStmtCastExpr"))
72311118Sdim      llvm::errs() << "PostStmt<CastExpr> (Kind : " << CE->getCastKindName()
73311118Sdim                   << ")\n";
74311118Sdim  }
75311118Sdim
76321369Sdim  void checkPreStmt(const ArraySubscriptExpr *SubExpr,
77321369Sdim                    CheckerContext &C) const {
78311118Sdim    if (isCallbackEnabled(C, "PreStmtArraySubscriptExpr"))
79311118Sdim      llvm::errs() << "PreStmt<ArraySubscriptExpr>\n";
80311118Sdim  }
81311118Sdim
82321369Sdim  void checkPostStmt(const ArraySubscriptExpr *SubExpr,
83321369Sdim                     CheckerContext &C) const {
84311118Sdim    if (isCallbackEnabled(C, "PostStmtArraySubscriptExpr"))
85311118Sdim      llvm::errs() << "PostStmt<ArraySubscriptExpr>\n";
86311118Sdim  }
87321369Sdim
88341825Sdim  void checkPreStmt(const CXXNewExpr *NE, CheckerContext &C) const {
89341825Sdim    if (isCallbackEnabled(C, "PreStmtCXXNewExpr"))
90341825Sdim      llvm::errs() << "PreStmt<CXXNewExpr>\n";
91341825Sdim  }
92341825Sdim
93341825Sdim  void checkPostStmt(const CXXNewExpr *NE, CheckerContext &C) const {
94341825Sdim    if (isCallbackEnabled(C, "PostStmtCXXNewExpr"))
95341825Sdim      llvm::errs() << "PostStmt<CXXNewExpr>\n";
96341825Sdim  }
97341825Sdim
98341825Sdim  void checkPreStmt(const OffsetOfExpr *OOE, CheckerContext &C) const {
99341825Sdim    if (isCallbackEnabled(C, "PreStmtOffsetOfExpr"))
100341825Sdim      llvm::errs() << "PreStmt<OffsetOfExpr>\n";
101341825Sdim  }
102341825Sdim
103341825Sdim  void checkPostStmt(const OffsetOfExpr *OOE, CheckerContext &C) const {
104341825Sdim    if (isCallbackEnabled(C, "PostStmtOffsetOfExpr"))
105341825Sdim      llvm::errs() << "PostStmt<OffsetOfExpr>\n";
106341825Sdim  }
107341825Sdim
108341825Sdim  void checkPreCall(const CallEvent &Call, CheckerContext &C) const {
109341825Sdim    if (isCallbackEnabled(C, "PreCall")) {
110341825Sdim      llvm::errs() << "PreCall";
111341825Sdim      if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Call.getDecl()))
112341825Sdim        llvm::errs() << " (" << ND->getQualifiedNameAsString() << ')';
113341825Sdim      llvm::errs() << '\n';
114341825Sdim    }
115341825Sdim  }
116341825Sdim
117341825Sdim  void checkPostCall(const CallEvent &Call, CheckerContext &C) const {
118341825Sdim    if (isCallbackEnabled(C, "PostCall")) {
119341825Sdim      llvm::errs() << "PostCall";
120341825Sdim      if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Call.getDecl()))
121341825Sdim        llvm::errs() << " (" << ND->getQualifiedNameAsString() << ')';
122341825Sdim      llvm::errs() << '\n';
123341825Sdim    }
124341825Sdim  }
125341825Sdim
126344779Sdim  void checkEndFunction(const ReturnStmt *S, CheckerContext &C) const {
127344779Sdim    if (isCallbackEnabled(C, "EndFunction")) {
128344779Sdim      llvm::errs() << "EndFunction\nReturnStmt: " << (S ? "yes" : "no") << "\n";
129344779Sdim      if (!S)
130344779Sdim        return;
131344779Sdim
132344779Sdim      llvm::errs() << "CFGElement: ";
133344779Sdim      CFGStmtMap *Map = C.getCurrentAnalysisDeclContext()->getCFGStmtMap();
134344779Sdim      CFGElement LastElement = Map->getBlock(S)->back();
135344779Sdim
136344779Sdim      if (LastElement.getAs<CFGStmt>())
137344779Sdim        llvm::errs() << "CFGStmt\n";
138344779Sdim      else if (LastElement.getAs<CFGAutomaticObjDtor>())
139344779Sdim        llvm::errs() << "CFGAutomaticObjDtor\n";
140344779Sdim    }
141344779Sdim  }
142344779Sdim
143341825Sdim  void checkNewAllocator(const CXXNewExpr *CNE, SVal Target,
144341825Sdim                         CheckerContext &C) const {
145341825Sdim    if (isCallbackEnabled(C, "NewAllocator"))
146341825Sdim      llvm::errs() << "NewAllocator\n";
147341825Sdim  }
148341825Sdim
149321369Sdim  void checkBind(SVal Loc, SVal Val, const Stmt *S, CheckerContext &C) const {
150321369Sdim    if (isCallbackEnabled(C, "Bind"))
151321369Sdim      llvm::errs() << "Bind\n";
152321369Sdim  }
153321369Sdim
154341825Sdim  void checkLiveSymbols(ProgramStateRef State, SymbolReaper &SymReaper) const {
155341825Sdim    if (isCallbackEnabled(State, "LiveSymbols"))
156341825Sdim      llvm::errs() << "LiveSymbols\n";
157341825Sdim  }
158341825Sdim
159321369Sdim  ProgramStateRef
160321369Sdim  checkRegionChanges(ProgramStateRef State,
161321369Sdim                     const InvalidatedSymbols *Invalidated,
162321369Sdim                     ArrayRef<const MemRegion *> ExplicitRegions,
163321369Sdim                     ArrayRef<const MemRegion *> Regions,
164321369Sdim                     const LocationContext *LCtx, const CallEvent *Call) const {
165321369Sdim    if (isCallbackEnabled(State, "RegionChanges"))
166321369Sdim      llvm::errs() << "RegionChanges\n";
167321369Sdim    return State;
168321369Sdim  }
169360784Sdim
170360784Sdim  ProgramStateRef checkPointerEscape(ProgramStateRef State,
171360784Sdim                                     const InvalidatedSymbols &Escaped,
172360784Sdim                                     const CallEvent *Call,
173360784Sdim                                     PointerEscapeKind Kind) const {
174360784Sdim    if (isCallbackEnabled(State, "PointerEscape"))
175360784Sdim      llvm::errs() << "PointerEscape\n";
176360784Sdim    return State;
177360784Sdim  }
178311118Sdim};
179321369Sdim} // end anonymous namespace
180311118Sdim
181311118Sdim//===----------------------------------------------------------------------===//
182311118Sdim// Registration.
183311118Sdim//===----------------------------------------------------------------------===//
184311118Sdim
185311118Sdimvoid ento::registerAnalysisOrderChecker(CheckerManager &mgr) {
186311118Sdim  mgr.registerChecker<AnalysisOrderChecker>();
187311118Sdim}
188353358Sdim
189353358Sdimbool ento::shouldRegisterAnalysisOrderChecker(const LangOptions &LO) {
190353358Sdim  return true;
191353358Sdim}
192