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