17330f729Sjoerg //== TraversalChecker.cpp -------------------------------------- -*- C++ -*--=//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg //
97330f729Sjoerg // These checkers print various aspects of the ExprEngine's traversal of the CFG
107330f729Sjoerg // as it builds the ExplodedGraph.
117330f729Sjoerg //
127330f729Sjoerg //===----------------------------------------------------------------------===//
137330f729Sjoerg #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
147330f729Sjoerg #include "clang/AST/ParentMap.h"
157330f729Sjoerg #include "clang/AST/StmtObjC.h"
167330f729Sjoerg #include "clang/StaticAnalyzer/Core/Checker.h"
177330f729Sjoerg #include "clang/StaticAnalyzer/Core/CheckerManager.h"
187330f729Sjoerg #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
197330f729Sjoerg #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
207330f729Sjoerg #include "llvm/Support/raw_ostream.h"
217330f729Sjoerg
227330f729Sjoerg using namespace clang;
237330f729Sjoerg using namespace ento;
247330f729Sjoerg
257330f729Sjoerg namespace {
267330f729Sjoerg class TraversalDumper : public Checker< check::BranchCondition,
277330f729Sjoerg check::BeginFunction,
287330f729Sjoerg check::EndFunction > {
297330f729Sjoerg public:
307330f729Sjoerg void checkBranchCondition(const Stmt *Condition, CheckerContext &C) const;
317330f729Sjoerg void checkBeginFunction(CheckerContext &C) const;
327330f729Sjoerg void checkEndFunction(const ReturnStmt *RS, CheckerContext &C) const;
337330f729Sjoerg };
347330f729Sjoerg }
357330f729Sjoerg
checkBranchCondition(const Stmt * Condition,CheckerContext & C) const367330f729Sjoerg void TraversalDumper::checkBranchCondition(const Stmt *Condition,
377330f729Sjoerg CheckerContext &C) const {
387330f729Sjoerg // Special-case Objective-C's for-in loop, which uses the entire loop as its
397330f729Sjoerg // condition. We just print the collection expression.
407330f729Sjoerg const Stmt *Parent = dyn_cast<ObjCForCollectionStmt>(Condition);
417330f729Sjoerg if (!Parent) {
427330f729Sjoerg const ParentMap &Parents = C.getLocationContext()->getParentMap();
437330f729Sjoerg Parent = Parents.getParent(Condition);
447330f729Sjoerg }
457330f729Sjoerg
467330f729Sjoerg // It is mildly evil to print directly to llvm::outs() rather than emitting
477330f729Sjoerg // warnings, but this ensures things do not get filtered out by the rest of
487330f729Sjoerg // the static analyzer machinery.
497330f729Sjoerg SourceLocation Loc = Parent->getBeginLoc();
507330f729Sjoerg llvm::outs() << C.getSourceManager().getSpellingLineNumber(Loc) << " "
517330f729Sjoerg << Parent->getStmtClassName() << "\n";
527330f729Sjoerg }
537330f729Sjoerg
checkBeginFunction(CheckerContext & C) const547330f729Sjoerg void TraversalDumper::checkBeginFunction(CheckerContext &C) const {
557330f729Sjoerg llvm::outs() << "--BEGIN FUNCTION--\n";
567330f729Sjoerg }
577330f729Sjoerg
checkEndFunction(const ReturnStmt * RS,CheckerContext & C) const587330f729Sjoerg void TraversalDumper::checkEndFunction(const ReturnStmt *RS,
597330f729Sjoerg CheckerContext &C) const {
607330f729Sjoerg llvm::outs() << "--END FUNCTION--\n";
617330f729Sjoerg }
627330f729Sjoerg
registerTraversalDumper(CheckerManager & mgr)637330f729Sjoerg void ento::registerTraversalDumper(CheckerManager &mgr) {
647330f729Sjoerg mgr.registerChecker<TraversalDumper>();
657330f729Sjoerg }
667330f729Sjoerg
shouldRegisterTraversalDumper(const CheckerManager & mgr)67*e038c9c4Sjoerg bool ento::shouldRegisterTraversalDumper(const CheckerManager &mgr) {
687330f729Sjoerg return true;
697330f729Sjoerg }
707330f729Sjoerg
717330f729Sjoerg //------------------------------------------------------------------------------
727330f729Sjoerg
737330f729Sjoerg namespace {
747330f729Sjoerg class CallDumper : public Checker< check::PreCall,
757330f729Sjoerg check::PostCall > {
767330f729Sjoerg public:
777330f729Sjoerg void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
787330f729Sjoerg void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
797330f729Sjoerg };
807330f729Sjoerg }
817330f729Sjoerg
checkPreCall(const CallEvent & Call,CheckerContext & C) const827330f729Sjoerg void CallDumper::checkPreCall(const CallEvent &Call, CheckerContext &C) const {
837330f729Sjoerg unsigned Indentation = 0;
847330f729Sjoerg for (const LocationContext *LC = C.getLocationContext()->getParent();
857330f729Sjoerg LC != nullptr; LC = LC->getParent())
867330f729Sjoerg ++Indentation;
877330f729Sjoerg
887330f729Sjoerg // It is mildly evil to print directly to llvm::outs() rather than emitting
897330f729Sjoerg // warnings, but this ensures things do not get filtered out by the rest of
907330f729Sjoerg // the static analyzer machinery.
917330f729Sjoerg llvm::outs().indent(Indentation);
927330f729Sjoerg Call.dump(llvm::outs());
937330f729Sjoerg }
947330f729Sjoerg
checkPostCall(const CallEvent & Call,CheckerContext & C) const957330f729Sjoerg void CallDumper::checkPostCall(const CallEvent &Call, CheckerContext &C) const {
967330f729Sjoerg const Expr *CallE = Call.getOriginExpr();
977330f729Sjoerg if (!CallE)
987330f729Sjoerg return;
997330f729Sjoerg
1007330f729Sjoerg unsigned Indentation = 0;
1017330f729Sjoerg for (const LocationContext *LC = C.getLocationContext()->getParent();
1027330f729Sjoerg LC != nullptr; LC = LC->getParent())
1037330f729Sjoerg ++Indentation;
1047330f729Sjoerg
1057330f729Sjoerg // It is mildly evil to print directly to llvm::outs() rather than emitting
1067330f729Sjoerg // warnings, but this ensures things do not get filtered out by the rest of
1077330f729Sjoerg // the static analyzer machinery.
1087330f729Sjoerg llvm::outs().indent(Indentation);
1097330f729Sjoerg if (Call.getResultType()->isVoidType())
1107330f729Sjoerg llvm::outs() << "Returning void\n";
1117330f729Sjoerg else
1127330f729Sjoerg llvm::outs() << "Returning " << C.getSVal(CallE) << "\n";
1137330f729Sjoerg }
1147330f729Sjoerg
registerCallDumper(CheckerManager & mgr)1157330f729Sjoerg void ento::registerCallDumper(CheckerManager &mgr) {
1167330f729Sjoerg mgr.registerChecker<CallDumper>();
1177330f729Sjoerg }
1187330f729Sjoerg
shouldRegisterCallDumper(const CheckerManager & mgr)119*e038c9c4Sjoerg bool ento::shouldRegisterCallDumper(const CheckerManager &mgr) {
1207330f729Sjoerg return true;
1217330f729Sjoerg }
122