1239313Sdim//== TraversalChecker.cpp -------------------------------------- -*- C++ -*--=//
2239313Sdim//
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
6239313Sdim//
7239313Sdim//===----------------------------------------------------------------------===//
8239313Sdim//
9239313Sdim// These checkers print various aspects of the ExprEngine's traversal of the CFG
10239313Sdim// as it builds the ExplodedGraph.
11239313Sdim//
12239313Sdim//===----------------------------------------------------------------------===//
13344779Sdim#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
14239313Sdim#include "clang/AST/ParentMap.h"
15239313Sdim#include "clang/AST/StmtObjC.h"
16239313Sdim#include "clang/StaticAnalyzer/Core/Checker.h"
17239313Sdim#include "clang/StaticAnalyzer/Core/CheckerManager.h"
18239313Sdim#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
19239313Sdim#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
20249423Sdim#include "llvm/Support/raw_ostream.h"
21239313Sdim
22239313Sdimusing namespace clang;
23239313Sdimusing namespace ento;
24239313Sdim
25239313Sdimnamespace {
26239313Sdimclass TraversalDumper : public Checker< check::BranchCondition,
27309124Sdim                                        check::BeginFunction,
28249423Sdim                                        check::EndFunction > {
29239313Sdimpublic:
30239313Sdim  void checkBranchCondition(const Stmt *Condition, CheckerContext &C) const;
31309124Sdim  void checkBeginFunction(CheckerContext &C) const;
32341825Sdim  void checkEndFunction(const ReturnStmt *RS, CheckerContext &C) const;
33239313Sdim};
34239313Sdim}
35239313Sdim
36239313Sdimvoid TraversalDumper::checkBranchCondition(const Stmt *Condition,
37239313Sdim                                           CheckerContext &C) const {
38239313Sdim  // Special-case Objective-C's for-in loop, which uses the entire loop as its
39239313Sdim  // condition. We just print the collection expression.
40239313Sdim  const Stmt *Parent = dyn_cast<ObjCForCollectionStmt>(Condition);
41239313Sdim  if (!Parent) {
42239313Sdim    const ParentMap &Parents = C.getLocationContext()->getParentMap();
43239313Sdim    Parent = Parents.getParent(Condition);
44239313Sdim  }
45239313Sdim
46239313Sdim  // It is mildly evil to print directly to llvm::outs() rather than emitting
47239313Sdim  // warnings, but this ensures things do not get filtered out by the rest of
48239313Sdim  // the static analyzer machinery.
49344779Sdim  SourceLocation Loc = Parent->getBeginLoc();
50239313Sdim  llvm::outs() << C.getSourceManager().getSpellingLineNumber(Loc) << " "
51239313Sdim               << Parent->getStmtClassName() << "\n";
52239313Sdim}
53239313Sdim
54309124Sdimvoid TraversalDumper::checkBeginFunction(CheckerContext &C) const {
55309124Sdim  llvm::outs() << "--BEGIN FUNCTION--\n";
56309124Sdim}
57309124Sdim
58341825Sdimvoid TraversalDumper::checkEndFunction(const ReturnStmt *RS,
59341825Sdim                                       CheckerContext &C) const {
60249423Sdim  llvm::outs() << "--END FUNCTION--\n";
61239313Sdim}
62239313Sdim
63239313Sdimvoid ento::registerTraversalDumper(CheckerManager &mgr) {
64239313Sdim  mgr.registerChecker<TraversalDumper>();
65239313Sdim}
66239313Sdim
67353358Sdimbool ento::shouldRegisterTraversalDumper(const LangOptions &LO) {
68353358Sdim  return true;
69353358Sdim}
70353358Sdim
71239313Sdim//------------------------------------------------------------------------------
72239313Sdim
73239313Sdimnamespace {
74249423Sdimclass CallDumper : public Checker< check::PreCall,
75249423Sdim                                   check::PostCall > {
76239313Sdimpublic:
77239313Sdim  void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
78249423Sdim  void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
79239313Sdim};
80239313Sdim}
81239313Sdim
82239313Sdimvoid CallDumper::checkPreCall(const CallEvent &Call, CheckerContext &C) const {
83239313Sdim  unsigned Indentation = 0;
84239313Sdim  for (const LocationContext *LC = C.getLocationContext()->getParent();
85276479Sdim       LC != nullptr; LC = LC->getParent())
86239313Sdim    ++Indentation;
87239313Sdim
88239313Sdim  // It is mildly evil to print directly to llvm::outs() rather than emitting
89239313Sdim  // warnings, but this ensures things do not get filtered out by the rest of
90239313Sdim  // the static analyzer machinery.
91239313Sdim  llvm::outs().indent(Indentation);
92239313Sdim  Call.dump(llvm::outs());
93239313Sdim}
94239313Sdim
95249423Sdimvoid CallDumper::checkPostCall(const CallEvent &Call, CheckerContext &C) const {
96249423Sdim  const Expr *CallE = Call.getOriginExpr();
97249423Sdim  if (!CallE)
98249423Sdim    return;
99249423Sdim
100249423Sdim  unsigned Indentation = 0;
101249423Sdim  for (const LocationContext *LC = C.getLocationContext()->getParent();
102276479Sdim       LC != nullptr; LC = LC->getParent())
103249423Sdim    ++Indentation;
104249423Sdim
105249423Sdim  // It is mildly evil to print directly to llvm::outs() rather than emitting
106249423Sdim  // warnings, but this ensures things do not get filtered out by the rest of
107249423Sdim  // the static analyzer machinery.
108249423Sdim  llvm::outs().indent(Indentation);
109249423Sdim  if (Call.getResultType()->isVoidType())
110249423Sdim    llvm::outs() << "Returning void\n";
111249423Sdim  else
112249423Sdim    llvm::outs() << "Returning " << C.getSVal(CallE) << "\n";
113249423Sdim}
114249423Sdim
115239313Sdimvoid ento::registerCallDumper(CheckerManager &mgr) {
116239313Sdim  mgr.registerChecker<CallDumper>();
117239313Sdim}
118353358Sdim
119353358Sdimbool ento::shouldRegisterCallDumper(const LangOptions &LO) {
120353358Sdim  return true;
121353358Sdim}
122