xref: /llvm-project/clang/unittests/StaticAnalyzer/MemRegionDescriptiveNameTest.cpp (revision 86d65ae7949e0322f10e1856c5c33caa34ebfe2f)
186d479fdST-Gruber //===- MemRegionDescriptiveNameTest.cpp -----------------------------------===//
286d479fdST-Gruber //
386d479fdST-Gruber // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
486d479fdST-Gruber // See https://llvm.org/LICENSE.txt for license information.
586d479fdST-Gruber // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
686d479fdST-Gruber //
786d479fdST-Gruber //===----------------------------------------------------------------------===//
886d479fdST-Gruber 
986d479fdST-Gruber #include "CheckerRegistration.h"
1086d479fdST-Gruber #include "clang/StaticAnalyzer/Core/Checker.h"
1186d479fdST-Gruber #include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
1286d479fdST-Gruber #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
1386d479fdST-Gruber #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
1486d479fdST-Gruber #include "gtest/gtest.h"
1586d479fdST-Gruber 
1686d479fdST-Gruber using namespace clang;
1786d479fdST-Gruber using namespace ento;
1886d479fdST-Gruber 
1986d479fdST-Gruber namespace {
2086d479fdST-Gruber 
2186d479fdST-Gruber class DescriptiveNameChecker : public Checker<check::PreCall> {
2286d479fdST-Gruber public:
2386d479fdST-Gruber   void checkPreCall(const CallEvent &Call, CheckerContext &C) const {
2486d479fdST-Gruber     if (!HandlerFn.matches(Call))
2586d479fdST-Gruber       return;
2686d479fdST-Gruber 
2786d479fdST-Gruber     const MemRegion *ArgReg = Call.getArgSVal(0).getAsRegion();
2886d479fdST-Gruber     assert(ArgReg && "expecting a location as the first argument");
2986d479fdST-Gruber 
3086d479fdST-Gruber     auto DescriptiveName = ArgReg->getDescriptiveName(/*UseQuotes=*/false);
3186d479fdST-Gruber     if (ExplodedNode *Node = C.generateNonFatalErrorNode(C.getState())) {
3286d479fdST-Gruber       auto Report =
3386d479fdST-Gruber           std::make_unique<PathSensitiveBugReport>(Bug, DescriptiveName, Node);
3486d479fdST-Gruber       C.emitReport(std::move(Report));
3586d479fdST-Gruber     }
3686d479fdST-Gruber   }
3786d479fdST-Gruber 
3886d479fdST-Gruber private:
3986d479fdST-Gruber   const BugType Bug{this, "DescriptiveNameBug"};
4058bad286SDonát Nagy   const CallDescription HandlerFn = {
4158bad286SDonát Nagy       CDM::SimpleFunc, {"reportDescriptiveName"}, 1};
4286d479fdST-Gruber };
4386d479fdST-Gruber 
4486d479fdST-Gruber void addDescriptiveNameChecker(AnalysisASTConsumer &AnalysisConsumer,
4586d479fdST-Gruber                                AnalyzerOptions &AnOpts) {
4686d479fdST-Gruber   AnOpts.CheckersAndPackages = {{"DescriptiveNameChecker", true}};
4786d479fdST-Gruber   AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) {
4886d479fdST-Gruber     Registry.addChecker<DescriptiveNameChecker>("DescriptiveNameChecker",
4986d479fdST-Gruber                                                 "Desc", "DocsURI");
5086d479fdST-Gruber   });
5186d479fdST-Gruber }
5286d479fdST-Gruber 
5386d479fdST-Gruber bool runChecker(StringRef Code, std::string &Output) {
5486d479fdST-Gruber   return runCheckerOnCode<addDescriptiveNameChecker>(Code.str(), Output,
5586d479fdST-Gruber                                                      /*OnlyEmitWarnings=*/true);
5686d479fdST-Gruber }
5786d479fdST-Gruber 
5886d479fdST-Gruber TEST(MemRegionDescriptiveNameTest, ConcreteIntElementRegionIndex) {
5986d479fdST-Gruber   StringRef Code = R"cpp(
6086d479fdST-Gruber void reportDescriptiveName(int *p);
6186d479fdST-Gruber const unsigned int index = 1;
6286d479fdST-Gruber extern int array[3];
6386d479fdST-Gruber void top() {
6486d479fdST-Gruber   reportDescriptiveName(&array[index]);
6586d479fdST-Gruber })cpp";
6686d479fdST-Gruber 
6786d479fdST-Gruber   std::string Output;
6886d479fdST-Gruber   ASSERT_TRUE(runChecker(Code, Output));
6986d479fdST-Gruber   EXPECT_EQ(Output, "DescriptiveNameChecker: array[1]\n");
7086d479fdST-Gruber }
7186d479fdST-Gruber 
7286d479fdST-Gruber TEST(MemRegionDescriptiveNameTest, SymbolicElementRegionIndex) {
7386d479fdST-Gruber   StringRef Code = R"cpp(
7486d479fdST-Gruber void reportDescriptiveName(int *p);
7586d479fdST-Gruber extern unsigned int index;
7686d479fdST-Gruber extern int array[3];
7786d479fdST-Gruber void top() {
7886d479fdST-Gruber   reportDescriptiveName(&array[index]);
7986d479fdST-Gruber })cpp";
8086d479fdST-Gruber 
8186d479fdST-Gruber   std::string Output;
8286d479fdST-Gruber   ASSERT_TRUE(runChecker(Code, Output));
8386d479fdST-Gruber   EXPECT_EQ(Output, "DescriptiveNameChecker: array[index]\n");
8486d479fdST-Gruber }
8586d479fdST-Gruber 
8686d479fdST-Gruber TEST(MemRegionDescriptiveNameTest, SymbolicElementRegionIndexSymbolValFails) {
8786d479fdST-Gruber   StringRef Code = R"cpp(
8886d479fdST-Gruber void reportDescriptiveName(int *p);
8986d479fdST-Gruber extern int* ptr;
9086d479fdST-Gruber extern int array[3];
9186d479fdST-Gruber void top() {
92f31b197dSMartin Storsjö   reportDescriptiveName(&array[(long long)ptr]);
9386d479fdST-Gruber })cpp";
9486d479fdST-Gruber 
9586d479fdST-Gruber   std::string Output;
9686d479fdST-Gruber   ASSERT_TRUE(runChecker(Code, Output));
9786d479fdST-Gruber   EXPECT_EQ(Output, "DescriptiveNameChecker: \n");
9886d479fdST-Gruber }
9986d479fdST-Gruber 
10086d479fdST-Gruber TEST(MemRegionDescriptiveNameTest, SymbolicElementRegionIndexOrigRegionFails) {
10186d479fdST-Gruber   StringRef Code = R"cpp(
10286d479fdST-Gruber void reportDescriptiveName(int *p);
10386d479fdST-Gruber extern int getInt(void);
10486d479fdST-Gruber extern int array[3];
10586d479fdST-Gruber void top() {
10686d479fdST-Gruber   reportDescriptiveName(&array[getInt()]);
10786d479fdST-Gruber })cpp";
10886d479fdST-Gruber 
10986d479fdST-Gruber   std::string Output;
11086d479fdST-Gruber   ASSERT_TRUE(runChecker(Code, Output));
11186d479fdST-Gruber   EXPECT_EQ(Output, "DescriptiveNameChecker: \n");
11286d479fdST-Gruber }
11386d479fdST-Gruber 
11486d479fdST-Gruber TEST(MemRegionDescriptiveNameTest, SymbolicElementRegionIndexDescrNameFails) {
11586d479fdST-Gruber   StringRef Code = R"cpp(
11686d479fdST-Gruber void reportDescriptiveName(int *p);
11786d479fdST-Gruber extern int *ptr;
11886d479fdST-Gruber extern int array[3];
11986d479fdST-Gruber void top() {
12086d479fdST-Gruber   reportDescriptiveName(&array[*ptr]);
12186d479fdST-Gruber })cpp";
12286d479fdST-Gruber 
12386d479fdST-Gruber   std::string Output;
12486d479fdST-Gruber   ASSERT_TRUE(runChecker(Code, Output));
12586d479fdST-Gruber   EXPECT_EQ(Output, "DescriptiveNameChecker: \n");
12686d479fdST-Gruber }
12786d479fdST-Gruber 
12886d479fdST-Gruber TEST(MemRegionDescriptiveNameTest,
12986d479fdST-Gruber      SymbolicElementRegionIndexIncorrectSymbolName) {
13086d479fdST-Gruber   StringRef Code = R"cpp(
13186d479fdST-Gruber void reportDescriptiveName(int *p);
13286d479fdST-Gruber extern int x, y;
13386d479fdST-Gruber extern int array[3];
13486d479fdST-Gruber void top() {
13586d479fdST-Gruber   y = x;
13686d479fdST-Gruber   reportDescriptiveName(&array[y]);
13786d479fdST-Gruber })cpp";
13886d479fdST-Gruber 
13986d479fdST-Gruber   std::string Output;
14086d479fdST-Gruber   ASSERT_TRUE(runChecker(Code, Output));
14186d479fdST-Gruber   // FIXME: Should return array[y], but returns array[x] (OriginRegion).
14286d479fdST-Gruber   EXPECT_EQ(Output, "DescriptiveNameChecker: array[x]\n");
14386d479fdST-Gruber }
14486d479fdST-Gruber 
145*86d65ae7ST-Gruber TEST(MemRegionDescriptiveNameTest, FieldRegWithSuperElementReg) {
146*86d65ae7ST-Gruber   StringRef Code = R"cpp(
147*86d65ae7ST-Gruber void reportDescriptiveName(int *p);
148*86d65ae7ST-Gruber struct val_struct { int val; };
149*86d65ae7ST-Gruber extern struct val_struct val_struct_array[3];
150*86d65ae7ST-Gruber void top() {
151*86d65ae7ST-Gruber   reportDescriptiveName(&val_struct_array[0].val);
152*86d65ae7ST-Gruber })cpp";
153*86d65ae7ST-Gruber 
154*86d65ae7ST-Gruber   std::string Output;
155*86d65ae7ST-Gruber   ASSERT_TRUE(runChecker(Code, Output));
156*86d65ae7ST-Gruber   EXPECT_EQ(Output, "DescriptiveNameChecker: val_struct_array[0].val\n");
157*86d65ae7ST-Gruber }
158*86d65ae7ST-Gruber 
159*86d65ae7ST-Gruber TEST(MemRegionDescriptiveNameTest, FieldRegWithSuperMultidimElementReg) {
160*86d65ae7ST-Gruber   StringRef Code = R"cpp(
161*86d65ae7ST-Gruber void reportDescriptiveName(int *p);
162*86d65ae7ST-Gruber struct val_struct { int val; };
163*86d65ae7ST-Gruber extern struct val_struct val_struct_array[3][4];
164*86d65ae7ST-Gruber void top() {
165*86d65ae7ST-Gruber   reportDescriptiveName(&val_struct_array[1][2].val);
166*86d65ae7ST-Gruber })cpp";
167*86d65ae7ST-Gruber 
168*86d65ae7ST-Gruber   std::string Output;
169*86d65ae7ST-Gruber   ASSERT_TRUE(runChecker(Code, Output));
170*86d65ae7ST-Gruber   EXPECT_EQ(Output, "DescriptiveNameChecker: val_struct_array[1][2].val\n");
171*86d65ae7ST-Gruber }
172*86d65ae7ST-Gruber 
17386d479fdST-Gruber } // namespace
174