|  | //===- MemRegionDescriptiveNameTest.cpp -----------------------------------===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "CheckerRegistration.h" | 
|  | #include "clang/StaticAnalyzer/Core/Checker.h" | 
|  | #include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h" | 
|  | #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" | 
|  | #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" | 
|  | #include "gtest/gtest.h" | 
|  |  | 
|  | using namespace clang; | 
|  | using namespace ento; | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | class DescriptiveNameChecker : public Checker<check::PreCall> { | 
|  | public: | 
|  | void checkPreCall(const CallEvent &Call, CheckerContext &C) const { | 
|  | if (!HandlerFn.matches(Call)) | 
|  | return; | 
|  |  | 
|  | const MemRegion *ArgReg = Call.getArgSVal(0).getAsRegion(); | 
|  | assert(ArgReg && "expecting a location as the first argument"); | 
|  |  | 
|  | auto DescriptiveName = ArgReg->getDescriptiveName(/*UseQuotes=*/false); | 
|  | if (ExplodedNode *Node = C.generateNonFatalErrorNode(C.getState())) { | 
|  | auto Report = | 
|  | std::make_unique<PathSensitiveBugReport>(Bug, DescriptiveName, Node); | 
|  | C.emitReport(std::move(Report)); | 
|  | } | 
|  | } | 
|  |  | 
|  | private: | 
|  | const BugType Bug{this, "DescriptiveNameBug"}; | 
|  | const CallDescription HandlerFn = { | 
|  | CDM::SimpleFunc, {"reportDescriptiveName"}, 1}; | 
|  | }; | 
|  |  | 
|  | void addDescriptiveNameChecker(AnalysisASTConsumer &AnalysisConsumer, | 
|  | AnalyzerOptions &AnOpts) { | 
|  | AnOpts.CheckersAndPackages = {{"DescriptiveNameChecker", true}}; | 
|  | AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) { | 
|  | Registry.addChecker<DescriptiveNameChecker>("DescriptiveNameChecker", | 
|  | "Desc", "DocsURI"); | 
|  | }); | 
|  | } | 
|  |  | 
|  | bool runChecker(StringRef Code, std::string &Output) { | 
|  | return runCheckerOnCode<addDescriptiveNameChecker>(Code.str(), Output, | 
|  | /*OnlyEmitWarnings=*/true); | 
|  | } | 
|  |  | 
|  | TEST(MemRegionDescriptiveNameTest, ConcreteIntElementRegionIndex) { | 
|  | StringRef Code = R"cpp( | 
|  | void reportDescriptiveName(int *p); | 
|  | const unsigned int index = 1; | 
|  | extern int array[3]; | 
|  | void top() { | 
|  | reportDescriptiveName(&array[index]); | 
|  | })cpp"; | 
|  |  | 
|  | std::string Output; | 
|  | ASSERT_TRUE(runChecker(Code, Output)); | 
|  | EXPECT_EQ(Output, "DescriptiveNameChecker: array[1]\n"); | 
|  | } | 
|  |  | 
|  | TEST(MemRegionDescriptiveNameTest, SymbolicElementRegionIndex) { | 
|  | StringRef Code = R"cpp( | 
|  | void reportDescriptiveName(int *p); | 
|  | extern unsigned int index; | 
|  | extern int array[3]; | 
|  | void top() { | 
|  | reportDescriptiveName(&array[index]); | 
|  | })cpp"; | 
|  |  | 
|  | std::string Output; | 
|  | ASSERT_TRUE(runChecker(Code, Output)); | 
|  | EXPECT_EQ(Output, "DescriptiveNameChecker: array[index]\n"); | 
|  | } | 
|  |  | 
|  | TEST(MemRegionDescriptiveNameTest, SymbolicElementRegionIndexSymbolValFails) { | 
|  | StringRef Code = R"cpp( | 
|  | void reportDescriptiveName(int *p); | 
|  | extern int* ptr; | 
|  | extern int array[3]; | 
|  | void top() { | 
|  | reportDescriptiveName(&array[(long long)ptr]); | 
|  | })cpp"; | 
|  |  | 
|  | std::string Output; | 
|  | ASSERT_TRUE(runChecker(Code, Output)); | 
|  | EXPECT_EQ(Output, "DescriptiveNameChecker: \n"); | 
|  | } | 
|  |  | 
|  | TEST(MemRegionDescriptiveNameTest, SymbolicElementRegionIndexOrigRegionFails) { | 
|  | StringRef Code = R"cpp( | 
|  | void reportDescriptiveName(int *p); | 
|  | extern int getInt(void); | 
|  | extern int array[3]; | 
|  | void top() { | 
|  | reportDescriptiveName(&array[getInt()]); | 
|  | })cpp"; | 
|  |  | 
|  | std::string Output; | 
|  | ASSERT_TRUE(runChecker(Code, Output)); | 
|  | EXPECT_EQ(Output, "DescriptiveNameChecker: \n"); | 
|  | } | 
|  |  | 
|  | TEST(MemRegionDescriptiveNameTest, SymbolicElementRegionIndexDescrNameFails) { | 
|  | StringRef Code = R"cpp( | 
|  | void reportDescriptiveName(int *p); | 
|  | extern int *ptr; | 
|  | extern int array[3]; | 
|  | void top() { | 
|  | reportDescriptiveName(&array[*ptr]); | 
|  | })cpp"; | 
|  |  | 
|  | std::string Output; | 
|  | ASSERT_TRUE(runChecker(Code, Output)); | 
|  | EXPECT_EQ(Output, "DescriptiveNameChecker: \n"); | 
|  | } | 
|  |  | 
|  | TEST(MemRegionDescriptiveNameTest, | 
|  | SymbolicElementRegionIndexIncorrectSymbolName) { | 
|  | StringRef Code = R"cpp( | 
|  | void reportDescriptiveName(int *p); | 
|  | extern int x, y; | 
|  | extern int array[3]; | 
|  | void top() { | 
|  | y = x; | 
|  | reportDescriptiveName(&array[y]); | 
|  | })cpp"; | 
|  |  | 
|  | std::string Output; | 
|  | ASSERT_TRUE(runChecker(Code, Output)); | 
|  | // FIXME: Should return array[y], but returns array[x] (OriginRegion). | 
|  | EXPECT_EQ(Output, "DescriptiveNameChecker: array[x]\n"); | 
|  | } | 
|  |  | 
|  | TEST(MemRegionDescriptiveNameTest, FieldRegWithSuperElementReg) { | 
|  | StringRef Code = R"cpp( | 
|  | void reportDescriptiveName(int *p); | 
|  | struct val_struct { int val; }; | 
|  | extern struct val_struct val_struct_array[3]; | 
|  | void top() { | 
|  | reportDescriptiveName(&val_struct_array[0].val); | 
|  | })cpp"; | 
|  |  | 
|  | std::string Output; | 
|  | ASSERT_TRUE(runChecker(Code, Output)); | 
|  | EXPECT_EQ(Output, "DescriptiveNameChecker: val_struct_array[0].val\n"); | 
|  | } | 
|  |  | 
|  | TEST(MemRegionDescriptiveNameTest, FieldRegWithSuperMultidimElementReg) { | 
|  | StringRef Code = R"cpp( | 
|  | void reportDescriptiveName(int *p); | 
|  | struct val_struct { int val; }; | 
|  | extern struct val_struct val_struct_array[3][4]; | 
|  | void top() { | 
|  | reportDescriptiveName(&val_struct_array[1][2].val); | 
|  | })cpp"; | 
|  |  | 
|  | std::string Output; | 
|  | ASSERT_TRUE(runChecker(Code, Output)); | 
|  | EXPECT_EQ(Output, "DescriptiveNameChecker: val_struct_array[1][2].val\n"); | 
|  | } | 
|  |  | 
|  | } // namespace |