Skip to content

Commit 86d65ae

Browse files
authored
[analyzer] Improve FieldRegion descriptive name (#112313)
The current implementation of MemRegion::getDescriptiveName fails for FieldRegions whose SuperRegion is an ElementRegion. As outlined below: ```Cpp struct val_struct { int val; }; extern struct val_struct val_struct_array[3]; void func(){ // FieldRegion with ElementRegion as SuperRegion. val_struct_array[0].val; } ``` For this special case, the expression cannot be pretty printed and must therefore be obtained separately.
1 parent 6bb6922 commit 86d65ae

File tree

2 files changed

+49
-7
lines changed

2 files changed

+49
-7
lines changed

clang/lib/StaticAnalyzer/Core/MemRegion.cpp

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -722,6 +722,13 @@ std::string MemRegion::getDescriptiveName(bool UseQuotes) const {
722722
SmallString<50> buf;
723723
llvm::raw_svector_ostream os(buf);
724724

725+
// Enclose subject with single quotes if needed.
726+
auto QuoteIfNeeded = [UseQuotes](const Twine &Subject) -> std::string {
727+
if (UseQuotes)
728+
return ("'" + Subject + "'").str();
729+
return Subject.str();
730+
};
731+
725732
// Obtain array indices to add them to the variable name.
726733
const ElementRegion *ER = nullptr;
727734
while ((ER = R->getAs<ElementRegion>())) {
@@ -751,12 +758,20 @@ std::string MemRegion::getDescriptiveName(bool UseQuotes) const {
751758
}
752759

753760
// Get variable name.
754-
if (R && R->canPrintPrettyAsExpr()) {
755-
R->printPrettyAsExpr(os);
756-
if (UseQuotes)
757-
return (llvm::Twine("'") + os.str() + ArrayIndices + "'").str();
758-
else
759-
return (llvm::Twine(os.str()) + ArrayIndices).str();
761+
if (R) {
762+
// MemRegion can be pretty printed.
763+
if (R->canPrintPrettyAsExpr()) {
764+
R->printPrettyAsExpr(os);
765+
return QuoteIfNeeded(llvm::Twine(os.str()) + ArrayIndices);
766+
}
767+
768+
// FieldRegion may have ElementRegion as SuperRegion.
769+
if (const auto *FR = R->getAs<FieldRegion>()) {
770+
std::string Super = FR->getSuperRegion()->getDescriptiveName(false);
771+
if (Super.empty())
772+
return "";
773+
return QuoteIfNeeded(Super + "." + FR->getDecl()->getName());
774+
}
760775
}
761776

762777
return VariableName;

clang/unittests/StaticAnalyzer/MemRegionDescriptiveNameTest.cpp

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
1313
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
1414
#include "gtest/gtest.h"
15-
#include <fstream>
1615

1716
using namespace clang;
1817
using namespace ento;
@@ -143,4 +142,32 @@ void top() {
143142
EXPECT_EQ(Output, "DescriptiveNameChecker: array[x]\n");
144143
}
145144

145+
TEST(MemRegionDescriptiveNameTest, FieldRegWithSuperElementReg) {
146+
StringRef Code = R"cpp(
147+
void reportDescriptiveName(int *p);
148+
struct val_struct { int val; };
149+
extern struct val_struct val_struct_array[3];
150+
void top() {
151+
reportDescriptiveName(&val_struct_array[0].val);
152+
})cpp";
153+
154+
std::string Output;
155+
ASSERT_TRUE(runChecker(Code, Output));
156+
EXPECT_EQ(Output, "DescriptiveNameChecker: val_struct_array[0].val\n");
157+
}
158+
159+
TEST(MemRegionDescriptiveNameTest, FieldRegWithSuperMultidimElementReg) {
160+
StringRef Code = R"cpp(
161+
void reportDescriptiveName(int *p);
162+
struct val_struct { int val; };
163+
extern struct val_struct val_struct_array[3][4];
164+
void top() {
165+
reportDescriptiveName(&val_struct_array[1][2].val);
166+
})cpp";
167+
168+
std::string Output;
169+
ASSERT_TRUE(runChecker(Code, Output));
170+
EXPECT_EQ(Output, "DescriptiveNameChecker: val_struct_array[1][2].val\n");
171+
}
172+
146173
} // namespace

0 commit comments

Comments
 (0)