blob: 7f715c9ba201f8368a47269b36b3cd23b3d717d2 [file] [log] [blame]
Jordy Rose31ae2592012-05-16 16:01:07 +00001//==- ExprInspectionChecker.cpp - Used for regression tests ------*- C++ -*-==//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Jordy Rose31ae2592012-05-16 16:01:07 +00006//
7//===----------------------------------------------------------------------===//
8
Kristof Umann76a21502018-12-15 16:23:51 +00009#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
Gabor Horvath3bd24f92017-10-30 12:02:23 +000010#include "clang/StaticAnalyzer/Checkers/SValExplainer.h"
Jordy Rose31ae2592012-05-16 16:01:07 +000011#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
Chandler Carruth3a022472012-12-04 09:13:33 +000012#include "clang/StaticAnalyzer/Core/Checker.h"
Gabor Horvath3bd24f92017-10-30 12:02:23 +000013#include "clang/StaticAnalyzer/Core/IssueHash.h"
Jordy Rose31ae2592012-05-16 16:01:07 +000014#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
Benjamin Kramerd7d2b1f2012-12-01 16:35:25 +000015#include "llvm/ADT/StringSwitch.h"
Pavel Labathd570a612017-01-16 15:57:07 +000016#include "llvm/Support/ScopedPrinter.h"
Jordy Rose31ae2592012-05-16 16:01:07 +000017
18using namespace clang;
19using namespace ento;
20
21namespace {
Artem Dergachev30ed5462016-11-30 17:57:18 +000022class ExprInspectionChecker : public Checker<eval::Call, check::DeadSymbols,
23 check::EndAnalysis> {
Ahmed Charlesb8984322014-03-07 20:03:18 +000024 mutable std::unique_ptr<BugType> BT;
Jordan Rose13937b12012-08-10 22:26:29 +000025
Artem Dergachev30ed5462016-11-30 17:57:18 +000026 // These stats are per-analysis, not per-branch, hence they shouldn't
27 // stay inside the program state.
28 struct ReachedStat {
29 ExplodedNode *ExampleNode;
30 unsigned NumTimesReached;
31 };
32 mutable llvm::DenseMap<const CallExpr *, ReachedStat> ReachedStats;
33
Jordan Rose13937b12012-08-10 22:26:29 +000034 void analyzerEval(const CallExpr *CE, CheckerContext &C) const;
35 void analyzerCheckInlined(const CallExpr *CE, CheckerContext &C) const;
Jordan Rose9db2d9a2013-10-03 16:57:03 +000036 void analyzerWarnIfReached(const CallExpr *CE, CheckerContext &C) const;
Artem Dergachev30ed5462016-11-30 17:57:18 +000037 void analyzerNumTimesReached(const CallExpr *CE, CheckerContext &C) const;
Jordan Rosee9c57222013-07-19 00:59:08 +000038 void analyzerCrash(const CallExpr *CE, CheckerContext &C) const;
Artem Dergachev733e71b2015-12-10 09:28:06 +000039 void analyzerWarnOnDeadSymbol(const CallExpr *CE, CheckerContext &C) const;
Artem Dergachev30ed5462016-11-30 17:57:18 +000040 void analyzerDump(const CallExpr *CE, CheckerContext &C) const;
Artem Dergachev895242f2016-01-15 15:22:05 +000041 void analyzerExplain(const CallExpr *CE, CheckerContext &C) const;
Artem Dergachev30ed5462016-11-30 17:57:18 +000042 void analyzerPrintState(const CallExpr *CE, CheckerContext &C) const;
Artem Dergachev895242f2016-01-15 15:22:05 +000043 void analyzerGetExtent(const CallExpr *CE, CheckerContext &C) const;
Gabor Horvath3bd24f92017-10-30 12:02:23 +000044 void analyzerHashDump(const CallExpr *CE, CheckerContext &C) const;
Artem Dergacheve527df02018-09-25 23:50:53 +000045 void analyzerDenote(const CallExpr *CE, CheckerContext &C) const;
46 void analyzerExpress(const CallExpr *CE, CheckerContext &C) const;
Jordan Rose13937b12012-08-10 22:26:29 +000047
48 typedef void (ExprInspectionChecker::*FnCheck)(const CallExpr *,
49 CheckerContext &C) const;
50
Artem Dergachev30ed5462016-11-30 17:57:18 +000051 ExplodedNode *reportBug(llvm::StringRef Msg, CheckerContext &C) const;
52 ExplodedNode *reportBug(llvm::StringRef Msg, BugReporter &BR,
53 ExplodedNode *N) const;
Artem Dergachev895242f2016-01-15 15:22:05 +000054
Jordy Rose31ae2592012-05-16 16:01:07 +000055public:
56 bool evalCall(const CallExpr *CE, CheckerContext &C) const;
Artem Dergachev733e71b2015-12-10 09:28:06 +000057 void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
Artem Dergachev30ed5462016-11-30 17:57:18 +000058 void checkEndAnalysis(ExplodedGraph &G, BugReporter &BR,
59 ExprEngine &Eng) const;
Jordy Rose31ae2592012-05-16 16:01:07 +000060};
Alexander Kornienkoab9db512015-06-22 23:07:51 +000061}
Jordy Rose31ae2592012-05-16 16:01:07 +000062
Artem Dergachev895242f2016-01-15 15:22:05 +000063REGISTER_SET_WITH_PROGRAMSTATE(MarkedSymbols, SymbolRef)
Artem Dergacheve527df02018-09-25 23:50:53 +000064REGISTER_MAP_WITH_PROGRAMSTATE(DenotedSymbols, SymbolRef, const StringLiteral *)
Artem Dergachev733e71b2015-12-10 09:28:06 +000065
Jordy Rose31ae2592012-05-16 16:01:07 +000066bool ExprInspectionChecker::evalCall(const CallExpr *CE,
Jordan Rose13937b12012-08-10 22:26:29 +000067 CheckerContext &C) const {
Jordy Rose31ae2592012-05-16 16:01:07 +000068 // These checks should have no effect on the surrounding environment
Jordan Rose13937b12012-08-10 22:26:29 +000069 // (globals should not be invalidated, etc), hence the use of evalCall.
70 FnCheck Handler = llvm::StringSwitch<FnCheck>(C.getCalleeName(CE))
71 .Case("clang_analyzer_eval", &ExprInspectionChecker::analyzerEval)
72 .Case("clang_analyzer_checkInlined",
73 &ExprInspectionChecker::analyzerCheckInlined)
Jordan Rosee9c57222013-07-19 00:59:08 +000074 .Case("clang_analyzer_crash", &ExprInspectionChecker::analyzerCrash)
Artem Dergachev733e71b2015-12-10 09:28:06 +000075 .Case("clang_analyzer_warnIfReached",
76 &ExprInspectionChecker::analyzerWarnIfReached)
77 .Case("clang_analyzer_warnOnDeadSymbol",
78 &ExprInspectionChecker::analyzerWarnOnDeadSymbol)
Anna Zaks37faed92017-03-09 00:01:10 +000079 .StartsWith("clang_analyzer_explain", &ExprInspectionChecker::analyzerExplain)
80 .StartsWith("clang_analyzer_dump", &ExprInspectionChecker::analyzerDump)
Artem Dergachev895242f2016-01-15 15:22:05 +000081 .Case("clang_analyzer_getExtent", &ExprInspectionChecker::analyzerGetExtent)
Artem Dergachev30ed5462016-11-30 17:57:18 +000082 .Case("clang_analyzer_printState",
83 &ExprInspectionChecker::analyzerPrintState)
84 .Case("clang_analyzer_numTimesReached",
85 &ExprInspectionChecker::analyzerNumTimesReached)
Gabor Horvath3bd24f92017-10-30 12:02:23 +000086 .Case("clang_analyzer_hashDump", &ExprInspectionChecker::analyzerHashDump)
Artem Dergacheve527df02018-09-25 23:50:53 +000087 .Case("clang_analyzer_denote", &ExprInspectionChecker::analyzerDenote)
88 .Case("clang_analyzer_express", &ExprInspectionChecker::analyzerExpress)
Craig Topper0dbb7832014-05-27 02:45:47 +000089 .Default(nullptr);
Jordan Rose13937b12012-08-10 22:26:29 +000090
91 if (!Handler)
92 return false;
93
94 (this->*Handler)(CE, C);
95 return true;
96}
97
98static const char *getArgumentValueString(const CallExpr *CE,
99 CheckerContext &C) {
100 if (CE->getNumArgs() == 0)
101 return "Missing assertion argument";
102
103 ExplodedNode *N = C.getPredecessor();
104 const LocationContext *LC = N->getLocationContext();
105 ProgramStateRef State = N->getState();
106
107 const Expr *Assertion = CE->getArg(0);
108 SVal AssertionVal = State->getSVal(Assertion, LC);
109
110 if (AssertionVal.isUndef())
111 return "UNDEFINED";
112
113 ProgramStateRef StTrue, StFalse;
Benjamin Kramer867ea1d2014-03-02 13:01:17 +0000114 std::tie(StTrue, StFalse) =
David Blaikie2fdacbc2013-02-20 05:52:05 +0000115 State->assume(AssertionVal.castAs<DefinedOrUnknownSVal>());
Jordan Rose13937b12012-08-10 22:26:29 +0000116
117 if (StTrue) {
118 if (StFalse)
119 return "UNKNOWN";
120 else
121 return "TRUE";
122 } else {
123 if (StFalse)
124 return "FALSE";
125 else
126 llvm_unreachable("Invalid constraint; neither true or false.");
127 }
128}
129
Artem Dergachev30ed5462016-11-30 17:57:18 +0000130ExplodedNode *ExprInspectionChecker::reportBug(llvm::StringRef Msg,
131 CheckerContext &C) const {
132 ExplodedNode *N = C.generateNonFatalErrorNode();
133 reportBug(Msg, C.getBugReporter(), N);
134 return N;
135}
136
137ExplodedNode *ExprInspectionChecker::reportBug(llvm::StringRef Msg,
138 BugReporter &BR,
139 ExplodedNode *N) const {
140 if (!N)
141 return nullptr;
142
Artem Dergachev895242f2016-01-15 15:22:05 +0000143 if (!BT)
144 BT.reset(new BugType(this, "Checking analyzer assumptions", "debug"));
145
Artem Dergachev30ed5462016-11-30 17:57:18 +0000146 BR.emitReport(llvm::make_unique<BugReport>(*BT, Msg, N));
147 return N;
Artem Dergachev895242f2016-01-15 15:22:05 +0000148}
149
Jordan Rose13937b12012-08-10 22:26:29 +0000150void ExprInspectionChecker::analyzerEval(const CallExpr *CE,
151 CheckerContext &C) const {
Devin Coughline39bd402015-09-16 22:03:05 +0000152 const LocationContext *LC = C.getPredecessor()->getLocationContext();
Jordy Rose31ae2592012-05-16 16:01:07 +0000153
Jordy Rose31ae2592012-05-16 16:01:07 +0000154 // A specific instantiation of an inlined function may have more constrained
155 // values than can generally be assumed. Skip the check.
George Karpenkovdd18b112018-06-27 01:51:55 +0000156 if (LC->getStackFrame()->getParent() != nullptr)
Jordan Rose13937b12012-08-10 22:26:29 +0000157 return;
Jordy Rose31ae2592012-05-16 16:01:07 +0000158
Artem Dergachev895242f2016-01-15 15:22:05 +0000159 reportBug(getArgumentValueString(CE, C), C);
Jordan Rose13937b12012-08-10 22:26:29 +0000160}
Jordy Rose31ae2592012-05-16 16:01:07 +0000161
Jordan Rose9db2d9a2013-10-03 16:57:03 +0000162void ExprInspectionChecker::analyzerWarnIfReached(const CallExpr *CE,
163 CheckerContext &C) const {
Artem Dergachev895242f2016-01-15 15:22:05 +0000164 reportBug("REACHABLE", C);
Jordan Rose9db2d9a2013-10-03 16:57:03 +0000165}
166
Artem Dergachev30ed5462016-11-30 17:57:18 +0000167void ExprInspectionChecker::analyzerNumTimesReached(const CallExpr *CE,
168 CheckerContext &C) const {
169 ++ReachedStats[CE].NumTimesReached;
170 if (!ReachedStats[CE].ExampleNode) {
171 // Later, in checkEndAnalysis, we'd throw a report against it.
172 ReachedStats[CE].ExampleNode = C.generateNonFatalErrorNode();
173 }
174}
175
Jordan Rose13937b12012-08-10 22:26:29 +0000176void ExprInspectionChecker::analyzerCheckInlined(const CallExpr *CE,
177 CheckerContext &C) const {
Devin Coughline39bd402015-09-16 22:03:05 +0000178 const LocationContext *LC = C.getPredecessor()->getLocationContext();
Jordan Rose13937b12012-08-10 22:26:29 +0000179
180 // An inlined function could conceivably also be analyzed as a top-level
181 // function. We ignore this case and only emit a message (TRUE or FALSE)
182 // when we are analyzing it as an inlined function. This means that
183 // clang_analyzer_checkInlined(true) should always print TRUE, but
184 // clang_analyzer_checkInlined(false) should never actually print anything.
George Karpenkovdd18b112018-06-27 01:51:55 +0000185 if (LC->getStackFrame()->getParent() == nullptr)
Jordan Rose13937b12012-08-10 22:26:29 +0000186 return;
187
Artem Dergachev895242f2016-01-15 15:22:05 +0000188 reportBug(getArgumentValueString(CE, C), C);
189}
Jordan Rose13937b12012-08-10 22:26:29 +0000190
Artem Dergachev895242f2016-01-15 15:22:05 +0000191void ExprInspectionChecker::analyzerExplain(const CallExpr *CE,
192 CheckerContext &C) const {
Artem Dergachev30ed5462016-11-30 17:57:18 +0000193 if (CE->getNumArgs() == 0) {
Artem Dergachev895242f2016-01-15 15:22:05 +0000194 reportBug("Missing argument for explaining", C);
Artem Dergachev30ed5462016-11-30 17:57:18 +0000195 return;
196 }
Artem Dergachev895242f2016-01-15 15:22:05 +0000197
198 SVal V = C.getSVal(CE->getArg(0));
199 SValExplainer Ex(C.getASTContext());
200 reportBug(Ex.Visit(V), C);
201}
202
Artem Dergachev30ed5462016-11-30 17:57:18 +0000203void ExprInspectionChecker::analyzerDump(const CallExpr *CE,
204 CheckerContext &C) const {
205 if (CE->getNumArgs() == 0) {
206 reportBug("Missing argument for dumping", C);
207 return;
208 }
209
210 SVal V = C.getSVal(CE->getArg(0));
211
212 llvm::SmallString<32> Str;
213 llvm::raw_svector_ostream OS(Str);
214 V.dumpToStream(OS);
215 reportBug(OS.str(), C);
216}
217
Artem Dergachev895242f2016-01-15 15:22:05 +0000218void ExprInspectionChecker::analyzerGetExtent(const CallExpr *CE,
219 CheckerContext &C) const {
Artem Dergachev30ed5462016-11-30 17:57:18 +0000220 if (CE->getNumArgs() == 0) {
Artem Dergachev895242f2016-01-15 15:22:05 +0000221 reportBug("Missing region for obtaining extent", C);
Artem Dergachev30ed5462016-11-30 17:57:18 +0000222 return;
223 }
Artem Dergachev895242f2016-01-15 15:22:05 +0000224
225 auto MR = dyn_cast_or_null<SubRegion>(C.getSVal(CE->getArg(0)).getAsRegion());
Artem Dergachev30ed5462016-11-30 17:57:18 +0000226 if (!MR) {
Artem Dergachev895242f2016-01-15 15:22:05 +0000227 reportBug("Obtaining extent of a non-region", C);
Artem Dergachev30ed5462016-11-30 17:57:18 +0000228 return;
229 }
Artem Dergachev895242f2016-01-15 15:22:05 +0000230
231 ProgramStateRef State = C.getState();
232 State = State->BindExpr(CE, C.getLocationContext(),
233 MR->getExtent(C.getSValBuilder()));
234 C.addTransition(State);
Jordy Rose31ae2592012-05-16 16:01:07 +0000235}
236
Artem Dergachev30ed5462016-11-30 17:57:18 +0000237void ExprInspectionChecker::analyzerPrintState(const CallExpr *CE,
238 CheckerContext &C) const {
239 C.getState()->dump();
240}
241
Artem Dergachev733e71b2015-12-10 09:28:06 +0000242void ExprInspectionChecker::analyzerWarnOnDeadSymbol(const CallExpr *CE,
243 CheckerContext &C) const {
244 if (CE->getNumArgs() == 0)
245 return;
246 SVal Val = C.getSVal(CE->getArg(0));
247 SymbolRef Sym = Val.getAsSymbol();
248 if (!Sym)
249 return;
250
251 ProgramStateRef State = C.getState();
252 State = State->add<MarkedSymbols>(Sym);
253 C.addTransition(State);
254}
255
256void ExprInspectionChecker::checkDeadSymbols(SymbolReaper &SymReaper,
257 CheckerContext &C) const {
258 ProgramStateRef State = C.getState();
259 const MarkedSymbolsTy &Syms = State->get<MarkedSymbols>();
Artem Dergachev30ed5462016-11-30 17:57:18 +0000260 ExplodedNode *N = C.getPredecessor();
Artem Dergachev733e71b2015-12-10 09:28:06 +0000261 for (auto I = Syms.begin(), E = Syms.end(); I != E; ++I) {
Artem Dergachev895242f2016-01-15 15:22:05 +0000262 SymbolRef Sym = *I;
Artem Dergachev733e71b2015-12-10 09:28:06 +0000263 if (!SymReaper.isDead(Sym))
264 continue;
265
Artem Dergachev30ed5462016-11-30 17:57:18 +0000266 // The non-fatal error node should be the same for all reports.
267 if (ExplodedNode *BugNode = reportBug("SYMBOL DEAD", C))
268 N = BugNode;
Artem Dergachev895242f2016-01-15 15:22:05 +0000269 State = State->remove<MarkedSymbols>(Sym);
Artem Dergachev733e71b2015-12-10 09:28:06 +0000270 }
Artem Dergacheve527df02018-09-25 23:50:53 +0000271
272 for (auto I : State->get<DenotedSymbols>()) {
273 SymbolRef Sym = I.first;
274 if (!SymReaper.isLive(Sym))
275 State = State->remove<DenotedSymbols>(Sym);
276 }
277
Artem Dergachev30ed5462016-11-30 17:57:18 +0000278 C.addTransition(State, N);
279}
280
281void ExprInspectionChecker::checkEndAnalysis(ExplodedGraph &G, BugReporter &BR,
282 ExprEngine &Eng) const {
283 for (auto Item: ReachedStats) {
284 unsigned NumTimesReached = Item.second.NumTimesReached;
285 ExplodedNode *N = Item.second.ExampleNode;
286
Pavel Labathd570a612017-01-16 15:57:07 +0000287 reportBug(llvm::to_string(NumTimesReached), BR, N);
Artem Dergachev30ed5462016-11-30 17:57:18 +0000288 }
Peter Szecsi657ac142017-07-25 19:23:23 +0000289 ReachedStats.clear();
Artem Dergachev733e71b2015-12-10 09:28:06 +0000290}
291
Jordan Rosee9c57222013-07-19 00:59:08 +0000292void ExprInspectionChecker::analyzerCrash(const CallExpr *CE,
293 CheckerContext &C) const {
294 LLVM_BUILTIN_TRAP;
295}
296
Gabor Horvath3bd24f92017-10-30 12:02:23 +0000297void ExprInspectionChecker::analyzerHashDump(const CallExpr *CE,
298 CheckerContext &C) const {
299 const LangOptions &Opts = C.getLangOpts();
300 const SourceManager &SM = C.getSourceManager();
Stephen Kellyf2ceec42018-08-09 21:08:08 +0000301 FullSourceLoc FL(CE->getArg(0)->getBeginLoc(), SM);
Gabor Horvath3bd24f92017-10-30 12:02:23 +0000302 std::string HashContent =
303 GetIssueString(SM, FL, getCheckName().getName(), "Category",
304 C.getLocationContext()->getDecl(), Opts);
305
306 reportBug(HashContent, C);
307}
308
Artem Dergacheve527df02018-09-25 23:50:53 +0000309void ExprInspectionChecker::analyzerDenote(const CallExpr *CE,
310 CheckerContext &C) const {
311 if (CE->getNumArgs() < 2) {
312 reportBug("clang_analyzer_denote() requires a symbol and a string literal",
313 C);
314 return;
315 }
316
317 SymbolRef Sym = C.getSVal(CE->getArg(0)).getAsSymbol();
318 if (!Sym) {
319 reportBug("Not a symbol", C);
320 return;
321 }
322
Artem Dergacheve527df02018-09-25 23:50:53 +0000323 const auto *E = dyn_cast<StringLiteral>(CE->getArg(1)->IgnoreParenCasts());
324 if (!E) {
325 reportBug("Not a string literal", C);
326 return;
327 }
328
329 ProgramStateRef State = C.getState();
330
331 C.addTransition(C.getState()->set<DenotedSymbols>(Sym, E));
332}
333
Benjamin Kramerc55e9972018-10-13 22:18:22 +0000334namespace {
Artem Dergacheve527df02018-09-25 23:50:53 +0000335class SymbolExpressor
336 : public SymExprVisitor<SymbolExpressor, Optional<std::string>> {
337 ProgramStateRef State;
338
339public:
340 SymbolExpressor(ProgramStateRef State) : State(State) {}
341
Artem Dergachev02955af2018-12-22 02:06:51 +0000342 Optional<std::string> lookup(const SymExpr *S) {
Artem Dergacheve527df02018-09-25 23:50:53 +0000343 if (const StringLiteral *const *SLPtr = State->get<DenotedSymbols>(S)) {
344 const StringLiteral *SL = *SLPtr;
345 return std::string(SL->getBytes());
346 }
347 return None;
348 }
349
Artem Dergachev02955af2018-12-22 02:06:51 +0000350 Optional<std::string> VisitSymExpr(const SymExpr *S) {
351 return lookup(S);
352 }
353
Artem Dergacheve527df02018-09-25 23:50:53 +0000354 Optional<std::string> VisitSymIntExpr(const SymIntExpr *S) {
Artem Dergachev02955af2018-12-22 02:06:51 +0000355 if (Optional<std::string> Str = lookup(S))
356 return Str;
357 if (Optional<std::string> Str = Visit(S->getLHS()))
Artem Dergacheve527df02018-09-25 23:50:53 +0000358 return (*Str + " " + BinaryOperator::getOpcodeStr(S->getOpcode()) + " " +
359 std::to_string(S->getRHS().getLimitedValue()) +
360 (S->getRHS().isUnsigned() ? "U" : ""))
361 .str();
362 return None;
363 }
364
365 Optional<std::string> VisitSymSymExpr(const SymSymExpr *S) {
Artem Dergachev02955af2018-12-22 02:06:51 +0000366 if (Optional<std::string> Str = lookup(S))
367 return Str;
368 if (Optional<std::string> Str1 = Visit(S->getLHS()))
369 if (Optional<std::string> Str2 = Visit(S->getRHS()))
Artem Dergacheve527df02018-09-25 23:50:53 +0000370 return (*Str1 + " " + BinaryOperator::getOpcodeStr(S->getOpcode()) +
371 " " + *Str2).str();
372 return None;
373 }
Artem Dergachev02955af2018-12-22 02:06:51 +0000374
375 Optional<std::string> VisitSymbolCast(const SymbolCast *S) {
376 if (Optional<std::string> Str = lookup(S))
377 return Str;
378 if (Optional<std::string> Str = Visit(S->getOperand()))
379 return (Twine("(") + S->getType().getAsString() + ")" + *Str).str();
380 return None;
381 }
Artem Dergacheve527df02018-09-25 23:50:53 +0000382};
Benjamin Kramerc55e9972018-10-13 22:18:22 +0000383} // namespace
Artem Dergacheve527df02018-09-25 23:50:53 +0000384
385void ExprInspectionChecker::analyzerExpress(const CallExpr *CE,
386 CheckerContext &C) const {
387 if (CE->getNumArgs() == 0) {
388 reportBug("clang_analyzer_express() requires a symbol", C);
389 return;
390 }
391
392 SymbolRef Sym = C.getSVal(CE->getArg(0)).getAsSymbol();
393 if (!Sym) {
394 reportBug("Not a symbol", C);
395 return;
396 }
397
398 SymbolExpressor V(C.getState());
399 auto Str = V.Visit(Sym);
400 if (!Str) {
401 reportBug("Unable to express", C);
402 return;
403 }
404
405 reportBug(*Str, C);
406}
407
Jordy Rose31ae2592012-05-16 16:01:07 +0000408void ento::registerExprInspectionChecker(CheckerManager &Mgr) {
409 Mgr.registerChecker<ExprInspectionChecker>();
410}
Kristof Umann058a7a42019-01-26 14:23:08 +0000411
412bool ento::shouldRegisterExprInspectionChecker(const LangOptions &LO) {
413 return true;
414}