1 //===- unittests/StaticAnalyzer/SValSimplifyerTest.cpp --------------------===//
3 // 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
7 //===----------------------------------------------------------------------===//
9 #include "CheckerRegistration.h"
10 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
11 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
12 #include "clang/StaticAnalyzer/Core/Checker.h"
13 #include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
14 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
15 #include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h"
16 #include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h"
17 #include "llvm/ADT/Twine.h"
18 #include "llvm/Support/raw_ostream.h"
19 #include "gtest/gtest.h"
21 using namespace clang
;
24 static std::string
toString(SVal V
) {
26 llvm::raw_string_ostream
Stream(Result
);
27 V
.dumpToStream(Stream
);
31 static void replace(std::string
&Content
, StringRef Substr
,
32 StringRef Replacement
) {
34 while ((Pos
= Content
.find(Substr
, Pos
)) != std::string::npos
) {
35 Content
.replace(Pos
, Substr
.size(), Replacement
);
36 Pos
+= Replacement
.size();
42 class SimplifyChecker
: public Checker
<check::PreCall
> {
43 const BugType Bug
{this, "SimplifyChecker"};
44 const CallDescription SimplifyCall
{CDM::SimpleFunc
, {"simplify"}, 1};
46 void report(CheckerContext
&C
, const Expr
*E
, StringRef Description
) const {
47 PathDiagnosticLocation
Loc(E
->getExprLoc(), C
.getSourceManager());
48 auto Report
= std::make_unique
<BasicBugReport
>(Bug
, Description
, Loc
);
49 C
.emitReport(std::move(Report
));
53 void checkPreCall(const CallEvent
&Call
, CheckerContext
&C
) const {
54 if (!SimplifyCall
.matches(Call
))
56 const Expr
*Arg
= Call
.getArgExpr(0);
57 SVal Val
= C
.getSVal(Arg
);
58 SVal SimplifiedVal
= C
.getSValBuilder().simplifySVal(C
.getState(), Val
);
59 std::string Subject
= toString(Val
);
60 std::string Simplified
= toString(SimplifiedVal
);
61 std::string Message
= (llvm::Twine
{Subject
} + " -> " + Simplified
).str();
62 report(C
, Arg
, Message
);
67 static void addSimplifyChecker(AnalysisASTConsumer
&AnalysisConsumer
,
68 AnalyzerOptions
&AnOpts
) {
69 AnOpts
.CheckersAndPackages
= {{"SimplifyChecker", true}};
70 AnalysisConsumer
.AddCheckerRegistrationFn([](CheckerRegistry
&Registry
) {
71 Registry
.addChecker
<SimplifyChecker
>("SimplifyChecker", "EmptyDescription",
76 static void runThisCheckerOnCode(const std::string
&Code
, std::string
&Diags
) {
77 ASSERT_TRUE(runCheckerOnCode
<addSimplifyChecker
>(Code
, Diags
,
78 /*OnlyEmitWarnings=*/true));
79 ASSERT_FALSE(Diags
.empty());
80 ASSERT_EQ(Diags
.back(), '\n');
86 TEST(SValSimplifyerTest
, LHSConstrainedNullPtrDiff
) {
87 constexpr auto Code
= R
"cpp(
88 template <class T> void simplify(T);
89 void LHSConstrainedNullPtrDiff(char *p, char *q) {
96 runThisCheckerOnCode(Code
, Diags
);
97 replace(Diags
, "(reg_$0<char * p>)", "reg_p");
98 replace(Diags
, "(reg_$1<char * q>)", "reg_q");
99 // This should not be simplified to "Unknown".
100 EXPECT_EQ(Diags
, "SimplifyChecker: reg_p - reg_q -> 0U - reg_q");