Skip to content

Commit d9853a8

Browse files
[clang-tidy][bugprone-posix-return] support integer literals as LHS (#109302)
Refactor matches to give more generic checker. --------- Co-authored-by: EugeneZelenko <[email protected]>
1 parent 3b96294 commit d9853a8

File tree

3 files changed

+62
-28
lines changed

3 files changed

+62
-28
lines changed

clang-tools-extra/clang-tidy/bugprone/PosixReturnCheck.cpp

Lines changed: 35 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -7,52 +7,58 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "PosixReturnCheck.h"
10-
#include "../utils/Matchers.h"
1110
#include "clang/AST/ASTContext.h"
1211
#include "clang/ASTMatchers/ASTMatchFinder.h"
12+
#include "clang/ASTMatchers/ASTMatchers.h"
1313
#include "clang/Lex/Lexer.h"
1414

1515
using namespace clang::ast_matchers;
1616

1717
namespace clang::tidy::bugprone {
1818

19-
static StringRef getFunctionSpelling(const MatchFinder::MatchResult &Result,
20-
const char *BindingStr) {
21-
const CallExpr *MatchedCall = cast<CallExpr>(
22-
(Result.Nodes.getNodeAs<BinaryOperator>(BindingStr))->getLHS());
19+
static StringRef getFunctionSpelling(const MatchFinder::MatchResult &Result) {
20+
const auto *MatchedCall = Result.Nodes.getNodeAs<CallExpr>("call");
2321
const SourceManager &SM = *Result.SourceManager;
2422
return Lexer::getSourceText(CharSourceRange::getTokenRange(
2523
MatchedCall->getCallee()->getSourceRange()),
2624
SM, Result.Context->getLangOpts());
2725
}
2826

2927
void PosixReturnCheck::registerMatchers(MatchFinder *Finder) {
28+
const auto PosixCall =
29+
callExpr(callee(functionDecl(
30+
anyOf(matchesName("^::posix_"), matchesName("^::pthread_")),
31+
unless(hasName("::posix_openpt")))))
32+
.bind("call");
33+
const auto ZeroIntegerLiteral = integerLiteral(equals(0));
34+
const auto NegIntegerLiteral =
35+
unaryOperator(hasOperatorName("-"), hasUnaryOperand(integerLiteral()));
36+
3037
Finder->addMatcher(
3138
binaryOperator(
32-
hasOperatorName("<"),
33-
hasLHS(callExpr(callee(functionDecl(
34-
anyOf(matchesName("^::posix_"), matchesName("^::pthread_")),
35-
unless(hasName("::posix_openpt")))))),
36-
hasRHS(integerLiteral(equals(0))))
39+
anyOf(allOf(hasOperatorName("<"), hasLHS(PosixCall),
40+
hasRHS(ZeroIntegerLiteral)),
41+
allOf(hasOperatorName(">"), hasLHS(ZeroIntegerLiteral),
42+
hasRHS(PosixCall))))
3743
.bind("ltzop"),
3844
this);
3945
Finder->addMatcher(
4046
binaryOperator(
41-
hasOperatorName(">="),
42-
hasLHS(callExpr(callee(functionDecl(
43-
anyOf(matchesName("^::posix_"), matchesName("^::pthread_")),
44-
unless(hasName("::posix_openpt")))))),
45-
hasRHS(integerLiteral(equals(0))))
47+
anyOf(allOf(hasOperatorName(">="), hasLHS(PosixCall),
48+
hasRHS(ZeroIntegerLiteral)),
49+
allOf(hasOperatorName("<="), hasLHS(ZeroIntegerLiteral),
50+
hasRHS(PosixCall))))
4651
.bind("atop"),
4752
this);
53+
Finder->addMatcher(binaryOperator(hasAnyOperatorName("==", "!="),
54+
hasOperands(PosixCall, NegIntegerLiteral))
55+
.bind("binop"),
56+
this);
4857
Finder->addMatcher(
49-
binaryOperator(
50-
hasAnyOperatorName("==", "!=", "<=", "<"),
51-
hasLHS(callExpr(callee(functionDecl(
52-
anyOf(matchesName("^::posix_"), matchesName("^::pthread_")),
53-
unless(hasName("::posix_openpt")))))),
54-
hasRHS(unaryOperator(hasOperatorName("-"),
55-
hasUnaryOperand(integerLiteral()))))
58+
binaryOperator(anyOf(allOf(hasAnyOperatorName("<=", "<"),
59+
hasLHS(PosixCall), hasRHS(NegIntegerLiteral)),
60+
allOf(hasAnyOperatorName(">", ">="),
61+
hasLHS(NegIntegerLiteral), hasRHS(PosixCall))))
5662
.bind("binop"),
5763
this);
5864
}
@@ -61,23 +67,26 @@ void PosixReturnCheck::check(const MatchFinder::MatchResult &Result) {
6167
if (const auto *LessThanZeroOp =
6268
Result.Nodes.getNodeAs<BinaryOperator>("ltzop")) {
6369
SourceLocation OperatorLoc = LessThanZeroOp->getOperatorLoc();
70+
StringRef NewBinOp =
71+
LessThanZeroOp->getOpcode() == BinaryOperator::Opcode::BO_LT ? ">"
72+
: "<";
6473
diag(OperatorLoc, "the comparison always evaluates to false because %0 "
6574
"always returns non-negative values")
66-
<< getFunctionSpelling(Result, "ltzop")
67-
<< FixItHint::CreateReplacement(OperatorLoc, Twine(">").str());
75+
<< getFunctionSpelling(Result)
76+
<< FixItHint::CreateReplacement(OperatorLoc, NewBinOp);
6877
return;
6978
}
7079
if (const auto *AlwaysTrueOp =
7180
Result.Nodes.getNodeAs<BinaryOperator>("atop")) {
7281
diag(AlwaysTrueOp->getOperatorLoc(),
7382
"the comparison always evaluates to true because %0 always returns "
7483
"non-negative values")
75-
<< getFunctionSpelling(Result, "atop");
84+
<< getFunctionSpelling(Result);
7685
return;
7786
}
7887
const auto *BinOp = Result.Nodes.getNodeAs<BinaryOperator>("binop");
7988
diag(BinOp->getOperatorLoc(), "%0 only returns non-negative values")
80-
<< getFunctionSpelling(Result, "binop");
89+
<< getFunctionSpelling(Result);
8190
}
8291

8392
} // namespace clang::tidy::bugprone

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,10 @@ Changes in existing checks
125125
<clang-tidy/checks/bugprone/forwarding-reference-overload>` check by fixing
126126
a crash when determining if an ``enable_if[_t]`` was found.
127127

128+
- Improved :doc:`bugprone-posix-return
129+
<clang-tidy/checks/bugprone/posix-return>` check to support integer literals
130+
as LHS and posix call as RHS of comparison.
131+
128132
- Improved :doc:`bugprone-sizeof-expression
129133
<clang-tidy/checks/bugprone/sizeof-expression>` check to find suspicious
130134
usages of ``sizeof()``, ``alignof()``, and ``offsetof()`` when adding or

clang-tools-extra/test/clang-tidy/checkers/bugprone/posix-return.cpp

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,9 @@ void warningLessThanZero() {
7474
if (pthread_yield() < 0) {}
7575
// CHECK-MESSAGES: :[[@LINE-1]]:23: warning:
7676
// CHECK-FIXES: pthread_yield() > 0
77+
if (0 > pthread_yield() ) {}
78+
// CHECK-MESSAGES: :[[@LINE-1]]:9: warning:
79+
// CHECK-FIXES: 0 < pthread_yield()
7780

7881
}
7982

@@ -90,7 +93,8 @@ void warningAlwaysTrue() {
9093
// CHECK-MESSAGES: :[[@LINE-1]]:31: warning:
9194
if (pthread_yield() >= 0) {}
9295
// CHECK-MESSAGES: :[[@LINE-1]]:23: warning:
93-
96+
if (0 <= pthread_yield()) {}
97+
// CHECK-MESSAGES: :[[@LINE-1]]:9: warning:
9498
}
9599

96100
void warningEqualsNegative() {
@@ -120,7 +124,14 @@ void warningEqualsNegative() {
120124
// CHECK-MESSAGES: :[[@LINE-1]]:46: warning:
121125
if (pthread_create(NULL, NULL, NULL, NULL) < -1) {}
122126
// CHECK-MESSAGES: :[[@LINE-1]]:46: warning:
123-
127+
if (-1 == pthread_create(NULL, NULL, NULL, NULL)) {}
128+
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning:
129+
if (-1 != pthread_create(NULL, NULL, NULL, NULL)) {}
130+
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning:
131+
if (-1 >= pthread_create(NULL, NULL, NULL, NULL)) {}
132+
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning:
133+
if (-1 > pthread_create(NULL, NULL, NULL, NULL)) {}
134+
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning:
124135
}
125136

126137
void WarningWithMacro() {
@@ -162,6 +173,16 @@ void noWarning() {
162173
if (posix_openpt(0) < -1) {}
163174
if (posix_fadvise(0, 0, 0, 0) <= 0) {}
164175
if (posix_fadvise(0, 0, 0, 0) == 1) {}
176+
if (0 > posix_openpt(0)) {}
177+
if (0 >= posix_openpt(0)) {}
178+
if (-1 == posix_openpt(0)) {}
179+
if (-1 != posix_openpt(0)) {}
180+
if (-1 >= posix_openpt(0)) {}
181+
if (-1 > posix_openpt(0)) {}
182+
if (posix_fadvise(0, 0, 0, 0) <= 0) {}
183+
if (posix_fadvise(0, 0, 0, 0) == 1) {}
184+
if (0 >= posix_fadvise(0, 0, 0, 0)) {}
185+
if (1 == posix_fadvise(0, 0, 0, 0)) {}
165186
}
166187

167188
namespace i {

0 commit comments

Comments
 (0)