Skip to content

Commit 278c0f8

Browse files
"readability check to convert numerical constants to std::numeric_limits"
1 parent 7a78ba2 commit 278c0f8

File tree

2 files changed

+22
-38
lines changed

2 files changed

+22
-38
lines changed

clang-tools-extra/clang-tidy/readability/NumericlimitmaxcheckCheck.cpp

Lines changed: 20 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,6 @@ void NumericlimitmaxcheckCheck::registerMatchers(MatchFinder *Finder) {
3838
if (!getLangOpts().CPlusPlus)
3939
return;
4040

41-
// ... inside registerMatchers() ...
42-
4341
auto NegOneLiteral = integerLiteral(equals(-1));
4442
auto ZeroLiteral = integerLiteral(equals(0));
4543

@@ -73,48 +71,43 @@ void NumericlimitmaxcheckCheck::registerMatchers(MatchFinder *Finder) {
7371
auto UnsignedLiteralNegOne =
7472
integerLiteral(equals(-1), hasType(isUnsignedInteger()));
7573

76-
// *** ADD THIS NEW MATCHER ***
77-
// Matches -1 or ~0 when they are a branch of a ternary operator
78-
// that is itself being implicitly cast to unsigned.
74+
// To handle ternary branch case
7975
auto TernaryBranch =
8076
expr(anyOf(NegOneExpr, BitNotZero),
81-
hasAncestor( // <-- Use hasAncestor to look up the tree
82-
conditionalOperator(
83-
// Check that the conditional operator itself has an ancestor
84-
// which is the implicit cast to unsigned
85-
hasAncestor(implicitCastExpr(hasType(isUnsignedInteger()))
77+
hasAncestor(conditionalOperator(
78+
hasAncestor(implicitCastExpr(hasType(isUnsignedInteger()
79+
))
8680
.bind("outerCast")))))
8781
.bind("unsignedMaxExpr");
8882

89-
// *** MODIFY THIS PART ***
90-
auto OldCombined =
83+
auto Combined =
9184
expr(anyOf(
9285
ExplicitCastOfNegOrBitnot,
9386
ImplicitNegOneToUnsigned,
9487
UnsignedBitNotZero,
9588
UnsignedLiteralNegOne
9689
)).bind("unsignedMaxExpr");
9790

98-
Finder->addMatcher(OldCombined, this);
99-
Finder->addMatcher(TernaryBranch, this); // Add the new matcher
91+
Finder->addMatcher(Combined, this);
92+
Finder->addMatcher(TernaryBranch, this);
10093
}
10194

10295

10396
void NumericlimitmaxcheckCheck::check(const MatchFinder::MatchResult &Result) {
104-
const auto *E = Result.Nodes.getNodeAs<Expr>("unsignedMaxExpr");
105-
const auto *OuterCast = Result.Nodes.getNodeAs<CastExpr>("outerCast"); // Get the cast
97+
const auto *E = Result.Nodes.getNodeAs<Expr>("unsignedMaxExpr");
98+
const auto *OuterCast = Result.Nodes.getNodeAs<CastExpr>("outerCast");
10699

107100
if (!E)
108101
return;
109102

110-
ASTContext &Ctx = *Result.Context; // Get context *before* first use
103+
ASTContext &Ctx = *Result.Context; // Get context before first use
111104

112105
QualType QT;
113106
if (OuterCast) {
114-
// This is our new ternary matcher. Get type from the *cast*.
107+
// This is ternary matcher. Get type from the cast.
115108
QT = OuterCast->getType();
116109
} else {
117-
// This is the old logic. Get type from the bound expression.
110+
// Get type from the bound expression.
118111
QT = E->getType();
119112
}
120113

@@ -123,19 +116,14 @@ const auto *E = Result.Nodes.getNodeAs<Expr>("unsignedMaxExpr");
123116

124117
const SourceManager &SM = Ctx.getSourceManager();
125118

126-
// *** ADD THIS LOGIC BLOCK ***
127-
// This logic prevents double-reporting for the *old* matchers.
128-
// We skip it for the new ternary matcher (when OuterCast is not null)
129-
// because the ternary matcher binds the *inner* expression, and we
130-
// *do* want to report it.
131119
if (!OuterCast) {
132-
auto Parents = Ctx.getParents(*E); // This fixes the [-Wunused] warning
120+
auto Parents = Ctx.getParents(*E);
133121
if (!Parents.empty()) {
134122
for (const auto &Parent : Parents) {
135123
// Check if parent is an explicit cast to unsigned
136124
if (const auto *ParentCast = Parent.get<ExplicitCastExpr>()) {
137125
if (ParentCast->getType()->isUnsignedIntegerType()) {
138-
// Skip this match - the cast itself will be (or was) reported
126+
// Skip this match, avoids double reporting
139127
return;
140128
}
141129
}
@@ -153,14 +141,10 @@ const auto *E = Result.Nodes.getNodeAs<Expr>("unsignedMaxExpr");
153141
}
154142
}
155143
}
156-
// ... (rest of parent checking logic) ...
157-
// ...
158-
// Determine the unsigned destination type
159-
// QualType QT = E->getType(); // This line is moved up and modified
144+
160145
if (QT.isNull() || !QT->isUnsignedIntegerType())
161146
return;
162147

163-
// Get a printable type string
164148
std::string TypeStr = QT.getUnqualifiedType().getAsString();
165149
if (const auto *Typedef = QT->getAs<TypedefType>()) {
166150
TypeStr = Typedef->getDecl()->getName().str();
@@ -171,22 +155,22 @@ const auto *E = Result.Nodes.getNodeAs<Expr>("unsignedMaxExpr");
171155
Lexer::getSourceText(CharSourceRange::getTokenRange(E->getSourceRange()),
172156
SM, getLangOpts());
173157

174-
// Build replacement text
158+
// Suggestion to the user regarding the usage of unsigned ~0 or -1
175159
std::string Replacement = "std::numeric_limits<" + TypeStr + ">::max()";
176160

177-
// Create diagnostic
161+
//gives warning message if unsigned ~0 or -1 are used instead of numeric_limit::max()
178162
auto Diag = diag(E->getBeginLoc(),
179163
"use 'std::numeric_limits<%0>::max()' instead of '%1'")
180164
<< TypeStr << OriginalText;
181165

182-
// Add fix-it hints
166+
//suggest hint for fixing it
183167
Diag << FixItHint::CreateReplacement(E->getSourceRange(), Replacement);
184168

185-
// Add include for <limits>
169+
//includes the <limits> which contains the numeric_limits::max()
186170
FileID FID = SM.getFileID(E->getBeginLoc());
187171
if (auto IncludeHint = Inserter.createIncludeInsertion(FID, "<limits>")) {
188172
Diag << *IncludeHint;
189173
}
190174
}
191175

192-
} // namespace clang::tidy::readability
176+
} // namespace clang::tidy::readability

clang-tools-extra/test/clang-tidy/checkers/readability/NumericLimitMaxCheck.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// RUN: %check_clang_tidy %s readability-NumericLimitMaxCheck %t
22

3-
// Defines a typedef, which the check should respect and use in its fix.
3+
44
typedef unsigned long long my_uint_t;
55

66
void test_arg(unsigned int);
@@ -98,4 +98,4 @@ void test_no_warning() {
9898
// The check should ignore code from macros
9999
unsigned m = MY_MAX_MACRO;
100100
unsigned m2 = MY_MAX_MACRO_TILDE;
101-
}
101+
}

0 commit comments

Comments
 (0)