1 //==- ExprInspectionChecker.cpp - Used for regression tests ------*- C++ -*-==//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "ClangSACheckers.h"
11 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
12 #include "clang/StaticAnalyzer/Core/Checker.h"
13 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
14 #include "llvm/ADT/StringSwitch.h"
16 using namespace clang;
20 class ExprInspectionChecker : public Checker< eval::Call > {
21 mutable OwningPtr<BugType> BT;
23 void analyzerEval(const CallExpr *CE, CheckerContext &C) const;
24 void analyzerCheckInlined(const CallExpr *CE, CheckerContext &C) const;
25 void analyzerWarnIfReached(const CallExpr *CE, CheckerContext &C) const;
26 void analyzerCrash(const CallExpr *CE, CheckerContext &C) const;
28 typedef void (ExprInspectionChecker::*FnCheck)(const CallExpr *,
29 CheckerContext &C) const;
32 bool evalCall(const CallExpr *CE, CheckerContext &C) const;
36 bool ExprInspectionChecker::evalCall(const CallExpr *CE,
37 CheckerContext &C) const {
38 // These checks should have no effect on the surrounding environment
39 // (globals should not be invalidated, etc), hence the use of evalCall.
40 FnCheck Handler = llvm::StringSwitch<FnCheck>(C.getCalleeName(CE))
41 .Case("clang_analyzer_eval", &ExprInspectionChecker::analyzerEval)
42 .Case("clang_analyzer_checkInlined",
43 &ExprInspectionChecker::analyzerCheckInlined)
44 .Case("clang_analyzer_crash", &ExprInspectionChecker::analyzerCrash)
45 .Case("clang_analyzer_warnIfReached", &ExprInspectionChecker::analyzerWarnIfReached)
51 (this->*Handler)(CE, C);
55 static const char *getArgumentValueString(const CallExpr *CE,
57 if (CE->getNumArgs() == 0)
58 return "Missing assertion argument";
60 ExplodedNode *N = C.getPredecessor();
61 const LocationContext *LC = N->getLocationContext();
62 ProgramStateRef State = N->getState();
64 const Expr *Assertion = CE->getArg(0);
65 SVal AssertionVal = State->getSVal(Assertion, LC);
67 if (AssertionVal.isUndef())
70 ProgramStateRef StTrue, StFalse;
71 llvm::tie(StTrue, StFalse) =
72 State->assume(AssertionVal.castAs<DefinedOrUnknownSVal>());
83 llvm_unreachable("Invalid constraint; neither true or false.");
87 void ExprInspectionChecker::analyzerEval(const CallExpr *CE,
88 CheckerContext &C) const {
89 ExplodedNode *N = C.getPredecessor();
90 const LocationContext *LC = N->getLocationContext();
92 // A specific instantiation of an inlined function may have more constrained
93 // values than can generally be assumed. Skip the check.
94 if (LC->getCurrentStackFrame()->getParent() != 0)
98 BT.reset(new BugType("Checking analyzer assumptions", "debug"));
100 BugReport *R = new BugReport(*BT, getArgumentValueString(CE, C), N);
104 void ExprInspectionChecker::analyzerWarnIfReached(const CallExpr *CE,
105 CheckerContext &C) const {
106 ExplodedNode *N = C.getPredecessor();
109 BT.reset(new BugType("Checking analyzer assumptions", "debug"));
111 BugReport *R = new BugReport(*BT, "REACHABLE", N);
115 void ExprInspectionChecker::analyzerCheckInlined(const CallExpr *CE,
116 CheckerContext &C) const {
117 ExplodedNode *N = C.getPredecessor();
118 const LocationContext *LC = N->getLocationContext();
120 // An inlined function could conceivably also be analyzed as a top-level
121 // function. We ignore this case and only emit a message (TRUE or FALSE)
122 // when we are analyzing it as an inlined function. This means that
123 // clang_analyzer_checkInlined(true) should always print TRUE, but
124 // clang_analyzer_checkInlined(false) should never actually print anything.
125 if (LC->getCurrentStackFrame()->getParent() == 0)
129 BT.reset(new BugType("Checking analyzer assumptions", "debug"));
131 BugReport *R = new BugReport(*BT, getArgumentValueString(CE, C), N);
135 void ExprInspectionChecker::analyzerCrash(const CallExpr *CE,
136 CheckerContext &C) const {
140 void ento::registerExprInspectionChecker(CheckerManager &Mgr) {
141 Mgr.registerChecker<ExprInspectionChecker>();