xref: /llvm-project/clang/unittests/StaticAnalyzer/MemRegionDescriptiveNameTest.cpp (revision 58bad2862cf136f9483eb005bbfa6915d459b46d)
1 //===- MemRegionDescriptiveNameTest.cpp -----------------------------------===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "CheckerRegistration.h"
10 #include "clang/StaticAnalyzer/Core/Checker.h"
11 #include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
12 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
13 #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
14 #include "gtest/gtest.h"
15 #include <fstream>
16 
17 using namespace clang;
18 using namespace ento;
19 
20 namespace {
21 
22 class DescriptiveNameChecker : public Checker<check::PreCall> {
23 public:
24   void checkPreCall(const CallEvent &Call, CheckerContext &C) const {
25     if (!HandlerFn.matches(Call))
26       return;
27 
28     const MemRegion *ArgReg = Call.getArgSVal(0).getAsRegion();
29     assert(ArgReg && "expecting a location as the first argument");
30 
31     auto DescriptiveName = ArgReg->getDescriptiveName(/*UseQuotes=*/false);
32     if (ExplodedNode *Node = C.generateNonFatalErrorNode(C.getState())) {
33       auto Report =
34           std::make_unique<PathSensitiveBugReport>(Bug, DescriptiveName, Node);
35       C.emitReport(std::move(Report));
36     }
37   }
38 
39 private:
40   const BugType Bug{this, "DescriptiveNameBug"};
41   const CallDescription HandlerFn = {
42       CDM::SimpleFunc, {"reportDescriptiveName"}, 1};
43 };
44 
45 void addDescriptiveNameChecker(AnalysisASTConsumer &AnalysisConsumer,
46                                AnalyzerOptions &AnOpts) {
47   AnOpts.CheckersAndPackages = {{"DescriptiveNameChecker", true}};
48   AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) {
49     Registry.addChecker<DescriptiveNameChecker>("DescriptiveNameChecker",
50                                                 "Desc", "DocsURI");
51   });
52 }
53 
54 bool runChecker(StringRef Code, std::string &Output) {
55   return runCheckerOnCode<addDescriptiveNameChecker>(Code.str(), Output,
56                                                      /*OnlyEmitWarnings=*/true);
57 }
58 
59 TEST(MemRegionDescriptiveNameTest, ConcreteIntElementRegionIndex) {
60   StringRef Code = R"cpp(
61 void reportDescriptiveName(int *p);
62 const unsigned int index = 1;
63 extern int array[3];
64 void top() {
65   reportDescriptiveName(&array[index]);
66 })cpp";
67 
68   std::string Output;
69   ASSERT_TRUE(runChecker(Code, Output));
70   EXPECT_EQ(Output, "DescriptiveNameChecker: array[1]\n");
71 }
72 
73 TEST(MemRegionDescriptiveNameTest, SymbolicElementRegionIndex) {
74   StringRef Code = R"cpp(
75 void reportDescriptiveName(int *p);
76 extern unsigned int index;
77 extern int array[3];
78 void top() {
79   reportDescriptiveName(&array[index]);
80 })cpp";
81 
82   std::string Output;
83   ASSERT_TRUE(runChecker(Code, Output));
84   EXPECT_EQ(Output, "DescriptiveNameChecker: array[index]\n");
85 }
86 
87 TEST(MemRegionDescriptiveNameTest, SymbolicElementRegionIndexSymbolValFails) {
88   StringRef Code = R"cpp(
89 void reportDescriptiveName(int *p);
90 extern int* ptr;
91 extern int array[3];
92 void top() {
93   reportDescriptiveName(&array[(long)ptr]);
94 })cpp";
95 
96   std::string Output;
97   ASSERT_TRUE(runChecker(Code, Output));
98   EXPECT_EQ(Output, "DescriptiveNameChecker: \n");
99 }
100 
101 TEST(MemRegionDescriptiveNameTest, SymbolicElementRegionIndexOrigRegionFails) {
102   StringRef Code = R"cpp(
103 void reportDescriptiveName(int *p);
104 extern int getInt(void);
105 extern int array[3];
106 void top() {
107   reportDescriptiveName(&array[getInt()]);
108 })cpp";
109 
110   std::string Output;
111   ASSERT_TRUE(runChecker(Code, Output));
112   EXPECT_EQ(Output, "DescriptiveNameChecker: \n");
113 }
114 
115 TEST(MemRegionDescriptiveNameTest, SymbolicElementRegionIndexDescrNameFails) {
116   StringRef Code = R"cpp(
117 void reportDescriptiveName(int *p);
118 extern int *ptr;
119 extern int array[3];
120 void top() {
121   reportDescriptiveName(&array[*ptr]);
122 })cpp";
123 
124   std::string Output;
125   ASSERT_TRUE(runChecker(Code, Output));
126   EXPECT_EQ(Output, "DescriptiveNameChecker: \n");
127 }
128 
129 TEST(MemRegionDescriptiveNameTest,
130      SymbolicElementRegionIndexIncorrectSymbolName) {
131   StringRef Code = R"cpp(
132 void reportDescriptiveName(int *p);
133 extern int x, y;
134 extern int array[3];
135 void top() {
136   y = x;
137   reportDescriptiveName(&array[y]);
138 })cpp";
139 
140   std::string Output;
141   ASSERT_TRUE(runChecker(Code, Output));
142   // FIXME: Should return array[y], but returns array[x] (OriginRegion).
143   EXPECT_EQ(Output, "DescriptiveNameChecker: array[x]\n");
144 }
145 
146 } // namespace
147