xref: /openbsd-src/gnu/llvm/clang/lib/StaticAnalyzer/Checkers/TraversalChecker.cpp (revision ec727ea710c91afd8ce4f788c5aaa8482b7b69b2)
1e5dd7070Spatrick //== TraversalChecker.cpp -------------------------------------- -*- C++ -*--=//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick //
9e5dd7070Spatrick // These checkers print various aspects of the ExprEngine's traversal of the CFG
10e5dd7070Spatrick // as it builds the ExplodedGraph.
11e5dd7070Spatrick //
12e5dd7070Spatrick //===----------------------------------------------------------------------===//
13e5dd7070Spatrick #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
14e5dd7070Spatrick #include "clang/AST/ParentMap.h"
15e5dd7070Spatrick #include "clang/AST/StmtObjC.h"
16e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/Checker.h"
17e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/CheckerManager.h"
18e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
19e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
20e5dd7070Spatrick #include "llvm/Support/raw_ostream.h"
21e5dd7070Spatrick 
22e5dd7070Spatrick using namespace clang;
23e5dd7070Spatrick using namespace ento;
24e5dd7070Spatrick 
25e5dd7070Spatrick namespace {
26e5dd7070Spatrick class TraversalDumper : public Checker< check::BranchCondition,
27e5dd7070Spatrick                                         check::BeginFunction,
28e5dd7070Spatrick                                         check::EndFunction > {
29e5dd7070Spatrick public:
30e5dd7070Spatrick   void checkBranchCondition(const Stmt *Condition, CheckerContext &C) const;
31e5dd7070Spatrick   void checkBeginFunction(CheckerContext &C) const;
32e5dd7070Spatrick   void checkEndFunction(const ReturnStmt *RS, CheckerContext &C) const;
33e5dd7070Spatrick };
34e5dd7070Spatrick }
35e5dd7070Spatrick 
checkBranchCondition(const Stmt * Condition,CheckerContext & C) const36e5dd7070Spatrick void TraversalDumper::checkBranchCondition(const Stmt *Condition,
37e5dd7070Spatrick                                            CheckerContext &C) const {
38e5dd7070Spatrick   // Special-case Objective-C's for-in loop, which uses the entire loop as its
39e5dd7070Spatrick   // condition. We just print the collection expression.
40e5dd7070Spatrick   const Stmt *Parent = dyn_cast<ObjCForCollectionStmt>(Condition);
41e5dd7070Spatrick   if (!Parent) {
42e5dd7070Spatrick     const ParentMap &Parents = C.getLocationContext()->getParentMap();
43e5dd7070Spatrick     Parent = Parents.getParent(Condition);
44e5dd7070Spatrick   }
45e5dd7070Spatrick 
46e5dd7070Spatrick   // It is mildly evil to print directly to llvm::outs() rather than emitting
47e5dd7070Spatrick   // warnings, but this ensures things do not get filtered out by the rest of
48e5dd7070Spatrick   // the static analyzer machinery.
49e5dd7070Spatrick   SourceLocation Loc = Parent->getBeginLoc();
50e5dd7070Spatrick   llvm::outs() << C.getSourceManager().getSpellingLineNumber(Loc) << " "
51e5dd7070Spatrick                << Parent->getStmtClassName() << "\n";
52e5dd7070Spatrick }
53e5dd7070Spatrick 
checkBeginFunction(CheckerContext & C) const54e5dd7070Spatrick void TraversalDumper::checkBeginFunction(CheckerContext &C) const {
55e5dd7070Spatrick   llvm::outs() << "--BEGIN FUNCTION--\n";
56e5dd7070Spatrick }
57e5dd7070Spatrick 
checkEndFunction(const ReturnStmt * RS,CheckerContext & C) const58e5dd7070Spatrick void TraversalDumper::checkEndFunction(const ReturnStmt *RS,
59e5dd7070Spatrick                                        CheckerContext &C) const {
60e5dd7070Spatrick   llvm::outs() << "--END FUNCTION--\n";
61e5dd7070Spatrick }
62e5dd7070Spatrick 
registerTraversalDumper(CheckerManager & mgr)63e5dd7070Spatrick void ento::registerTraversalDumper(CheckerManager &mgr) {
64e5dd7070Spatrick   mgr.registerChecker<TraversalDumper>();
65e5dd7070Spatrick }
66e5dd7070Spatrick 
shouldRegisterTraversalDumper(const CheckerManager & mgr)67*ec727ea7Spatrick bool ento::shouldRegisterTraversalDumper(const CheckerManager &mgr) {
68e5dd7070Spatrick   return true;
69e5dd7070Spatrick }
70e5dd7070Spatrick 
71e5dd7070Spatrick //------------------------------------------------------------------------------
72e5dd7070Spatrick 
73e5dd7070Spatrick namespace {
74e5dd7070Spatrick class CallDumper : public Checker< check::PreCall,
75e5dd7070Spatrick                                    check::PostCall > {
76e5dd7070Spatrick public:
77e5dd7070Spatrick   void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
78e5dd7070Spatrick   void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
79e5dd7070Spatrick };
80e5dd7070Spatrick }
81e5dd7070Spatrick 
checkPreCall(const CallEvent & Call,CheckerContext & C) const82e5dd7070Spatrick void CallDumper::checkPreCall(const CallEvent &Call, CheckerContext &C) const {
83e5dd7070Spatrick   unsigned Indentation = 0;
84e5dd7070Spatrick   for (const LocationContext *LC = C.getLocationContext()->getParent();
85e5dd7070Spatrick        LC != nullptr; LC = LC->getParent())
86e5dd7070Spatrick     ++Indentation;
87e5dd7070Spatrick 
88e5dd7070Spatrick   // It is mildly evil to print directly to llvm::outs() rather than emitting
89e5dd7070Spatrick   // warnings, but this ensures things do not get filtered out by the rest of
90e5dd7070Spatrick   // the static analyzer machinery.
91e5dd7070Spatrick   llvm::outs().indent(Indentation);
92e5dd7070Spatrick   Call.dump(llvm::outs());
93e5dd7070Spatrick }
94e5dd7070Spatrick 
checkPostCall(const CallEvent & Call,CheckerContext & C) const95e5dd7070Spatrick void CallDumper::checkPostCall(const CallEvent &Call, CheckerContext &C) const {
96e5dd7070Spatrick   const Expr *CallE = Call.getOriginExpr();
97e5dd7070Spatrick   if (!CallE)
98e5dd7070Spatrick     return;
99e5dd7070Spatrick 
100e5dd7070Spatrick   unsigned Indentation = 0;
101e5dd7070Spatrick   for (const LocationContext *LC = C.getLocationContext()->getParent();
102e5dd7070Spatrick        LC != nullptr; LC = LC->getParent())
103e5dd7070Spatrick     ++Indentation;
104e5dd7070Spatrick 
105e5dd7070Spatrick   // It is mildly evil to print directly to llvm::outs() rather than emitting
106e5dd7070Spatrick   // warnings, but this ensures things do not get filtered out by the rest of
107e5dd7070Spatrick   // the static analyzer machinery.
108e5dd7070Spatrick   llvm::outs().indent(Indentation);
109e5dd7070Spatrick   if (Call.getResultType()->isVoidType())
110e5dd7070Spatrick     llvm::outs() << "Returning void\n";
111e5dd7070Spatrick   else
112e5dd7070Spatrick     llvm::outs() << "Returning " << C.getSVal(CallE) << "\n";
113e5dd7070Spatrick }
114e5dd7070Spatrick 
registerCallDumper(CheckerManager & mgr)115e5dd7070Spatrick void ento::registerCallDumper(CheckerManager &mgr) {
116e5dd7070Spatrick   mgr.registerChecker<CallDumper>();
117e5dd7070Spatrick }
118e5dd7070Spatrick 
shouldRegisterCallDumper(const CheckerManager & mgr)119*ec727ea7Spatrick bool ento::shouldRegisterCallDumper(const CheckerManager &mgr) {
120e5dd7070Spatrick   return true;
121e5dd7070Spatrick }
122