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