1//== TraversalChecker.cpp -------------------------------------- -*- 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// These checkers print various aspects of the ExprEngine's traversal of the CFG
10// as it builds the ExplodedGraph.
11//
12//===----------------------------------------------------------------------===//
13#include "clang/AST/ParentMap.h"
14#include "clang/AST/StmtObjC.h"
15#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
16#include "clang/StaticAnalyzer/Core/Checker.h"
17#include "clang/StaticAnalyzer/Core/CheckerManager.h"
18#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
19#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
20#include "llvm/Support/raw_ostream.h"
21#include <iterator>
22
23using namespace clang;
24using namespace ento;
25
26namespace {
27// TODO: This checker is only referenced from two small test files and it
28// doesn't seem to be useful for manual debugging, so consider reimplementing
29// those tests with more modern tools and removing this checker.
30class TraversalDumper
31 : public Checker<check::BeginFunction, check::EndFunction> {
32public:
33 void checkBeginFunction(CheckerContext &C) const;
34 void checkEndFunction(const ReturnStmt *RS, CheckerContext &C) const;
35};
36}
37
38void TraversalDumper::checkBeginFunction(CheckerContext &C) const {
39 llvm::outs() << "--BEGIN FUNCTION--\n";
40}
41
42void TraversalDumper::checkEndFunction(const ReturnStmt *RS,
43 CheckerContext &C) const {
44 llvm::outs() << "--END FUNCTION--\n";
45}
46
47void ento::registerTraversalDumper(CheckerManager &mgr) {
48 mgr.registerChecker<TraversalDumper>();
49}
50
51bool ento::shouldRegisterTraversalDumper(const CheckerManager &mgr) {
52 return true;
53}
54
55//------------------------------------------------------------------------------
56
57namespace {
58// TODO: This checker appears to be a utility for creating `FileCheck` tests
59// verifying its stdout output, but there are no tests that rely on it, so
60// perhaps it should be removed.
61class CallDumper : public Checker< check::PreCall,
62 check::PostCall > {
63public:
64 void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
65 void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
66};
67}
68
69void CallDumper::checkPreCall(const CallEvent &Call, CheckerContext &C) const {
70 auto Parents = C.getStackFrame()->parents();
71 unsigned Indentation = std::distance(first: Parents.begin(), last: Parents.end());
72
73 // It is mildly evil to print directly to llvm::outs() rather than emitting
74 // warnings, but this ensures things do not get filtered out by the rest of
75 // the static analyzer machinery.
76 llvm::outs().indent(NumSpaces: Indentation);
77 Call.dump(Out&: llvm::outs());
78}
79
80void CallDumper::checkPostCall(const CallEvent &Call, CheckerContext &C) const {
81 const Expr *CallE = Call.getOriginExpr();
82 if (!CallE)
83 return;
84
85 auto Parents = C.getStackFrame()->parents();
86 unsigned Indentation = std::distance(first: Parents.begin(), last: Parents.end());
87
88 // It is mildly evil to print directly to llvm::outs() rather than emitting
89 // warnings, but this ensures things do not get filtered out by the rest of
90 // the static analyzer machinery.
91 llvm::outs().indent(NumSpaces: Indentation);
92 if (Call.getResultType()->isVoidType())
93 llvm::outs() << "Returning void\n";
94 else
95 llvm::outs() << "Returning " << C.getSVal(E: CallE) << "\n";
96}
97
98void ento::registerCallDumper(CheckerManager &mgr) {
99 mgr.registerChecker<CallDumper>();
100}
101
102bool ento::shouldRegisterCallDumper(const CheckerManager &mgr) {
103 return true;
104}
105