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