Clang Project

clang_source_code/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp
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::RegionChanges,
44                     check::LiveSymbols> {
45
46  bool isCallbackEnabled(AnalyzerOptions &OptsStringRef CallbackNameconst {
47    return Opts.getCheckerBooleanOption(this"*"false) ||
48        Opts.getCheckerBooleanOption(this, CallbackName, false);
49  }
50
51  bool isCallbackEnabled(CheckerContext &CStringRef CallbackNameconst {
52    AnalyzerOptions &Opts = C.getAnalysisManager().getAnalyzerOptions();
53    return isCallbackEnabled(Opts, CallbackName);
54  }
55
56  bool isCallbackEnabled(ProgramStateRef StateStringRef CallbackNameconst {
57    AnalyzerOptions &Opts = State->getStateManager().getOwningEngine()
58                                 .getAnalysisManager().getAnalyzerOptions();
59    return isCallbackEnabled(Opts, CallbackName);
60  }
61
62public:
63  void checkPreStmt(const CastExpr *CECheckerContext &Cconst {
64    if (isCallbackEnabled(C, "PreStmtCastExpr"))
65      llvm::errs() << "PreStmt<CastExpr> (Kind : " << CE->getCastKindName()
66                   << ")\n";
67  }
68
69  void checkPostStmt(const CastExpr *CECheckerContext &Cconst {
70    if (isCallbackEnabled(C, "PostStmtCastExpr"))
71      llvm::errs() << "PostStmt<CastExpr> (Kind : " << CE->getCastKindName()
72                   << ")\n";
73  }
74
75  void checkPreStmt(const ArraySubscriptExpr *SubExpr,
76                    CheckerContext &Cconst {
77    if (isCallbackEnabled(C, "PreStmtArraySubscriptExpr"))
78      llvm::errs() << "PreStmt<ArraySubscriptExpr>\n";
79  }
80
81  void checkPostStmt(const ArraySubscriptExpr *SubExpr,
82                     CheckerContext &Cconst {
83    if (isCallbackEnabled(C, "PostStmtArraySubscriptExpr"))
84      llvm::errs() << "PostStmt<ArraySubscriptExpr>\n";
85  }
86
87  void checkPreStmt(const CXXNewExpr *NECheckerContext &Cconst {
88    if (isCallbackEnabled(C, "PreStmtCXXNewExpr"))
89      llvm::errs() << "PreStmt<CXXNewExpr>\n";
90  }
91
92  void checkPostStmt(const CXXNewExpr *NECheckerContext &Cconst {
93    if (isCallbackEnabled(C, "PostStmtCXXNewExpr"))
94      llvm::errs() << "PostStmt<CXXNewExpr>\n";
95  }
96
97  void checkPreStmt(const OffsetOfExpr *OOECheckerContext &Cconst {
98    if (isCallbackEnabled(C, "PreStmtOffsetOfExpr"))
99      llvm::errs() << "PreStmt<OffsetOfExpr>\n";
100  }
101
102  void checkPostStmt(const OffsetOfExpr *OOECheckerContext &Cconst {
103    if (isCallbackEnabled(C, "PostStmtOffsetOfExpr"))
104      llvm::errs() << "PostStmt<OffsetOfExpr>\n";
105  }
106
107  void checkPreCall(const CallEvent &CallCheckerContext &Cconst {
108    if (isCallbackEnabled(C"PreCall")) {
109      llvm::errs() << "PreCall";
110      if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Call.getDecl()))
111        llvm::errs() << " (" << ND->getQualifiedNameAsString() << ')';
112      llvm::errs() << '\n';
113    }
114  }
115
116  void checkPostCall(const CallEvent &CallCheckerContext &Cconst {
117    if (isCallbackEnabled(C"PostCall")) {
118      llvm::errs() << "PostCall";
119      if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Call.getDecl()))
120        llvm::errs() << " (" << ND->getQualifiedNameAsString() << ')';
121      llvm::errs() << '\n';
122    }
123  }
124
125  void checkEndFunction(const ReturnStmt *SCheckerContext &Cconst {
126    if (isCallbackEnabled(C"EndFunction")) {
127      llvm::errs() << "EndFunction\nReturnStmt: " << (S ? "yes" : "no") << "\n";
128      if (!S)
129        return;
130
131      llvm::errs() << "CFGElement: ";
132      CFGStmtMap *Map = C.getCurrentAnalysisDeclContext()->getCFGStmtMap();
133      CFGElement LastElement = Map->getBlock(S)->back();
134
135      if (LastElement.getAs<CFGStmt>())
136        llvm::errs() << "CFGStmt\n";
137      else if (LastElement.getAs<CFGAutomaticObjDtor>())
138        llvm::errs() << "CFGAutomaticObjDtor\n";
139    }
140  }
141
142  void checkNewAllocator(const CXXNewExpr *CNESVal Target,
143                         CheckerContext &Cconst {
144    if (isCallbackEnabled(C, "NewAllocator"))
145      llvm::errs() << "NewAllocator\n";
146  }
147
148  void checkBind(SVal LocSVal Valconst Stmt *SCheckerContext &Cconst {
149    if (isCallbackEnabled(C, "Bind"))
150      llvm::errs() << "Bind\n";
151  }
152
153  void checkLiveSymbols(ProgramStateRef StateSymbolReaper &SymReaperconst {
154    if (isCallbackEnabled(State, "LiveSymbols"))
155      llvm::errs() << "LiveSymbols\n";
156  }
157
158  ProgramStateRef
159  checkRegionChanges(ProgramStateRef State,
160                     const InvalidatedSymbols *Invalidated,
161                     ArrayRef<const MemRegion *> ExplicitRegions,
162                     ArrayRef<const MemRegion *> Regions,
163                     const LocationContext *LCtxconst CallEvent *Callconst {
164    if (isCallbackEnabled(State, "RegionChanges"))
165      llvm::errs() << "RegionChanges\n";
166    return State;
167  }
168};
169// end anonymous namespace
170
171//===----------------------------------------------------------------------===//
172// Registration.
173//===----------------------------------------------------------------------===//
174
175void ento::registerAnalysisOrderChecker(CheckerManager &mgr) {
176  mgr.registerChecker<AnalysisOrderChecker>();
177}
178
179bool ento::shouldRegisterAnalysisOrderChecker(const LangOptions &LO) {
180  return true;
181}
182