AnalysisOrderChecker.cpp revision 353358
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,
43341825Sdim                     check::RegionChanges,
44341825Sdim                     check::LiveSymbols> {
45341825Sdim
46321369Sdim  bool isCallbackEnabled(AnalyzerOptions &Opts, StringRef CallbackName) const {
47353358Sdim    return Opts.getCheckerBooleanOption(this, "*") ||
48353358Sdim           Opts.getCheckerBooleanOption(this, CallbackName);
49311118Sdim  }
50311118Sdim
51321369Sdim  bool isCallbackEnabled(CheckerContext &C, StringRef CallbackName) const {
52321369Sdim    AnalyzerOptions &Opts = C.getAnalysisManager().getAnalyzerOptions();
53321369Sdim    return isCallbackEnabled(Opts, CallbackName);
54321369Sdim  }
55321369Sdim
56321369Sdim  bool isCallbackEnabled(ProgramStateRef State, StringRef CallbackName) const {
57321369Sdim    AnalyzerOptions &Opts = State->getStateManager().getOwningEngine()
58344779Sdim                                 .getAnalysisManager().getAnalyzerOptions();
59321369Sdim    return isCallbackEnabled(Opts, CallbackName);
60321369Sdim  }
61321369Sdim
62311118Sdimpublic:
63311118Sdim  void checkPreStmt(const CastExpr *CE, CheckerContext &C) const {
64311118Sdim    if (isCallbackEnabled(C, "PreStmtCastExpr"))
65311118Sdim      llvm::errs() << "PreStmt<CastExpr> (Kind : " << CE->getCastKindName()
66311118Sdim                   << ")\n";
67311118Sdim  }
68311118Sdim
69311118Sdim  void checkPostStmt(const CastExpr *CE, CheckerContext &C) const {
70311118Sdim    if (isCallbackEnabled(C, "PostStmtCastExpr"))
71311118Sdim      llvm::errs() << "PostStmt<CastExpr> (Kind : " << CE->getCastKindName()
72311118Sdim                   << ")\n";
73311118Sdim  }
74311118Sdim
75321369Sdim  void checkPreStmt(const ArraySubscriptExpr *SubExpr,
76321369Sdim                    CheckerContext &C) const {
77311118Sdim    if (isCallbackEnabled(C, "PreStmtArraySubscriptExpr"))
78311118Sdim      llvm::errs() << "PreStmt<ArraySubscriptExpr>\n";
79311118Sdim  }
80311118Sdim
81321369Sdim  void checkPostStmt(const ArraySubscriptExpr *SubExpr,
82321369Sdim                     CheckerContext &C) const {
83311118Sdim    if (isCallbackEnabled(C, "PostStmtArraySubscriptExpr"))
84311118Sdim      llvm::errs() << "PostStmt<ArraySubscriptExpr>\n";
85311118Sdim  }
86321369Sdim
87341825Sdim  void checkPreStmt(const CXXNewExpr *NE, CheckerContext &C) const {
88341825Sdim    if (isCallbackEnabled(C, "PreStmtCXXNewExpr"))
89341825Sdim      llvm::errs() << "PreStmt<CXXNewExpr>\n";
90341825Sdim  }
91341825Sdim
92341825Sdim  void checkPostStmt(const CXXNewExpr *NE, CheckerContext &C) const {
93341825Sdim    if (isCallbackEnabled(C, "PostStmtCXXNewExpr"))
94341825Sdim      llvm::errs() << "PostStmt<CXXNewExpr>\n";
95341825Sdim  }
96341825Sdim
97341825Sdim  void checkPreStmt(const OffsetOfExpr *OOE, CheckerContext &C) const {
98341825Sdim    if (isCallbackEnabled(C, "PreStmtOffsetOfExpr"))
99341825Sdim      llvm::errs() << "PreStmt<OffsetOfExpr>\n";
100341825Sdim  }
101341825Sdim
102341825Sdim  void checkPostStmt(const OffsetOfExpr *OOE, CheckerContext &C) const {
103341825Sdim    if (isCallbackEnabled(C, "PostStmtOffsetOfExpr"))
104341825Sdim      llvm::errs() << "PostStmt<OffsetOfExpr>\n";
105341825Sdim  }
106341825Sdim
107341825Sdim  void checkPreCall(const CallEvent &Call, CheckerContext &C) const {
108341825Sdim    if (isCallbackEnabled(C, "PreCall")) {
109341825Sdim      llvm::errs() << "PreCall";
110341825Sdim      if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Call.getDecl()))
111341825Sdim        llvm::errs() << " (" << ND->getQualifiedNameAsString() << ')';
112341825Sdim      llvm::errs() << '\n';
113341825Sdim    }
114341825Sdim  }
115341825Sdim
116341825Sdim  void checkPostCall(const CallEvent &Call, CheckerContext &C) const {
117341825Sdim    if (isCallbackEnabled(C, "PostCall")) {
118341825Sdim      llvm::errs() << "PostCall";
119341825Sdim      if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Call.getDecl()))
120341825Sdim        llvm::errs() << " (" << ND->getQualifiedNameAsString() << ')';
121341825Sdim      llvm::errs() << '\n';
122341825Sdim    }
123341825Sdim  }
124341825Sdim
125344779Sdim  void checkEndFunction(const ReturnStmt *S, CheckerContext &C) const {
126344779Sdim    if (isCallbackEnabled(C, "EndFunction")) {
127344779Sdim      llvm::errs() << "EndFunction\nReturnStmt: " << (S ? "yes" : "no") << "\n";
128344779Sdim      if (!S)
129344779Sdim        return;
130344779Sdim
131344779Sdim      llvm::errs() << "CFGElement: ";
132344779Sdim      CFGStmtMap *Map = C.getCurrentAnalysisDeclContext()->getCFGStmtMap();
133344779Sdim      CFGElement LastElement = Map->getBlock(S)->back();
134344779Sdim
135344779Sdim      if (LastElement.getAs<CFGStmt>())
136344779Sdim        llvm::errs() << "CFGStmt\n";
137344779Sdim      else if (LastElement.getAs<CFGAutomaticObjDtor>())
138344779Sdim        llvm::errs() << "CFGAutomaticObjDtor\n";
139344779Sdim    }
140344779Sdim  }
141344779Sdim
142341825Sdim  void checkNewAllocator(const CXXNewExpr *CNE, SVal Target,
143341825Sdim                         CheckerContext &C) const {
144341825Sdim    if (isCallbackEnabled(C, "NewAllocator"))
145341825Sdim      llvm::errs() << "NewAllocator\n";
146341825Sdim  }
147341825Sdim
148321369Sdim  void checkBind(SVal Loc, SVal Val, const Stmt *S, CheckerContext &C) const {
149321369Sdim    if (isCallbackEnabled(C, "Bind"))
150321369Sdim      llvm::errs() << "Bind\n";
151321369Sdim  }
152321369Sdim
153341825Sdim  void checkLiveSymbols(ProgramStateRef State, SymbolReaper &SymReaper) const {
154341825Sdim    if (isCallbackEnabled(State, "LiveSymbols"))
155341825Sdim      llvm::errs() << "LiveSymbols\n";
156341825Sdim  }
157341825Sdim
158321369Sdim  ProgramStateRef
159321369Sdim  checkRegionChanges(ProgramStateRef State,
160321369Sdim                     const InvalidatedSymbols *Invalidated,
161321369Sdim                     ArrayRef<const MemRegion *> ExplicitRegions,
162321369Sdim                     ArrayRef<const MemRegion *> Regions,
163321369Sdim                     const LocationContext *LCtx, const CallEvent *Call) const {
164321369Sdim    if (isCallbackEnabled(State, "RegionChanges"))
165321369Sdim      llvm::errs() << "RegionChanges\n";
166321369Sdim    return State;
167321369Sdim  }
168311118Sdim};
169321369Sdim} // end anonymous namespace
170311118Sdim
171311118Sdim//===----------------------------------------------------------------------===//
172311118Sdim// Registration.
173311118Sdim//===----------------------------------------------------------------------===//
174311118Sdim
175311118Sdimvoid ento::registerAnalysisOrderChecker(CheckerManager &mgr) {
176311118Sdim  mgr.registerChecker<AnalysisOrderChecker>();
177311118Sdim}
178353358Sdim
179353358Sdimbool ento::shouldRegisterAnalysisOrderChecker(const LangOptions &LO) {
180353358Sdim  return true;
181353358Sdim}
182