Skip to content

Commit 6b70c32

Browse files
author
Endre Fülöp
committed
[analyzer] Extend EnumCastOutOfRange diagnostics
EnumCastOutOfRange checker now reports the name of the enum in the warning message. Additionally, a note-tag is placed to highlight the location of the declaration.
1 parent 8823e96 commit 6b70c32

File tree

3 files changed

+87
-67
lines changed

3 files changed

+87
-67
lines changed

clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ class ConstraintBasedEQEvaluator {
5959
// value can be matching.
6060
class EnumCastOutOfRangeChecker : public Checker<check::PreStmt<CastExpr>> {
6161
mutable std::unique_ptr<BugType> EnumValueCastOutOfRange;
62-
void reportWarning(CheckerContext &C) const;
62+
void reportWarning(CheckerContext &C, const EnumDecl *E) const;
6363

6464
public:
6565
void checkPreStmt(const CastExpr *CE, CheckerContext &C) const;
@@ -72,21 +72,36 @@ EnumValueVector getDeclValuesForEnum(const EnumDecl *ED) {
7272
EnumValueVector DeclValues(
7373
std::distance(ED->enumerator_begin(), ED->enumerator_end()));
7474
llvm::transform(ED->enumerators(), DeclValues.begin(),
75-
[](const EnumConstantDecl *D) { return D->getInitVal(); });
75+
[](const EnumConstantDecl *D) { return D->getInitVal(); });
7676
return DeclValues;
7777
}
7878
} // namespace
7979

80-
void EnumCastOutOfRangeChecker::reportWarning(CheckerContext &C) const {
80+
void EnumCastOutOfRangeChecker::reportWarning(CheckerContext &C,
81+
const EnumDecl *E) const {
82+
assert(E && "valid EnumDecl* is expected");
8183
if (const ExplodedNode *N = C.generateNonFatalErrorNode()) {
8284
if (!EnumValueCastOutOfRange)
8385
EnumValueCastOutOfRange.reset(
8486
new BugType(this, "Enum cast out of range"));
85-
constexpr llvm::StringLiteral Msg =
86-
"The value provided to the cast expression is not in the valid range"
87-
" of values for the enum";
88-
C.emitReport(std::make_unique<PathSensitiveBugReport>(
89-
*EnumValueCastOutOfRange, Msg, N));
87+
88+
llvm::SmallString<128> Msg{"The value provided to the cast expression is "
89+
"not in the valid range of values for "};
90+
StringRef EnumName{E->getName()};
91+
if (EnumName.empty()) {
92+
Msg += "the enum";
93+
} else {
94+
Msg += '\'';
95+
Msg += EnumName;
96+
Msg += '\'';
97+
}
98+
99+
auto BR = std::make_unique<PathSensitiveBugReport>(*EnumValueCastOutOfRange,
100+
Msg, N);
101+
BR->addNote("enum declared here",
102+
PathDiagnosticLocation::create(E, C.getSourceManager()),
103+
{E->getSourceRange()});
104+
C.emitReport(std::move(BR));
90105
}
91106
}
92107

@@ -144,7 +159,7 @@ void EnumCastOutOfRangeChecker::checkPreStmt(const CastExpr *CE,
144159
// If there is no value that can possibly match any of the enum values, then
145160
// warn.
146161
if (!PossibleValueMatch)
147-
reportWarning(C);
162+
reportWarning(C, ED);
148163
}
149164

150165
void ento::registerEnumCastOutOfRangeChecker(CheckerManager &mgr) {

clang/test/Analysis/enum-cast-out-of-range.c

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// RUN: -analyzer-checker=core,alpha.cplusplus.EnumCastOutOfRange \
33
// RUN: -verify %s
44

5+
// expected-note@+1 6 {{enum declared here}}
56
enum En_t {
67
En_0 = -4,
78
En_1,
@@ -11,17 +12,17 @@ enum En_t {
1112
};
1213

1314
void unscopedUnspecifiedCStyle(void) {
14-
enum En_t Below = (enum En_t)(-5); // expected-warning {{not in the valid range}}
15+
enum En_t Below = (enum En_t)(-5); // expected-warning {{not in the valid range of values for 'En_t'}}
1516
enum En_t NegVal1 = (enum En_t)(-4); // OK.
1617
enum En_t NegVal2 = (enum En_t)(-3); // OK.
17-
enum En_t InRange1 = (enum En_t)(-2); // expected-warning {{not in the valid range}}
18-
enum En_t InRange2 = (enum En_t)(-1); // expected-warning {{not in the valid range}}
19-
enum En_t InRange3 = (enum En_t)(0); // expected-warning {{not in the valid range}}
18+
enum En_t InRange1 = (enum En_t)(-2); // expected-warning {{not in the valid range of values for 'En_t'}}
19+
enum En_t InRange2 = (enum En_t)(-1); // expected-warning {{not in the valid range of values for 'En_t'}}
20+
enum En_t InRange3 = (enum En_t)(0); // expected-warning {{not in the valid range of values for 'En_t'}}
2021
enum En_t PosVal1 = (enum En_t)(1); // OK.
2122
enum En_t PosVal2 = (enum En_t)(2); // OK.
22-
enum En_t InRange4 = (enum En_t)(3); // expected-warning {{not in the valid range}}
23+
enum En_t InRange4 = (enum En_t)(3); // expected-warning {{not in the valid range of values for 'En_t'}}
2324
enum En_t PosVal3 = (enum En_t)(4); // OK.
24-
enum En_t Above = (enum En_t)(5); // expected-warning {{not in the valid range}}
25+
enum En_t Above = (enum En_t)(5); // expected-warning {{not in the valid range of values for 'En_t'}}
2526
}
2627

2728
enum En_t unused;

0 commit comments

Comments
 (0)