[clang-tidy][bugprone-posix-return] support integer literals as LHS (#109302)

Refactor matches to give more generic checker.

---------

Co-authored-by: EugeneZelenko <eugene.zelenko@gmail.com>
This commit is contained in:
Congcong Cai 2024-09-27 10:05:37 +08:00 committed by GitHub
parent 3b96294f2d
commit d9853a8a10
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 62 additions and 28 deletions

View File

@ -7,19 +7,17 @@
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#include "PosixReturnCheck.h" #include "PosixReturnCheck.h"
#include "../utils/Matchers.h"
#include "clang/AST/ASTContext.h" #include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/Lex/Lexer.h" #include "clang/Lex/Lexer.h"
using namespace clang::ast_matchers; using namespace clang::ast_matchers;
namespace clang::tidy::bugprone { namespace clang::tidy::bugprone {
static StringRef getFunctionSpelling(const MatchFinder::MatchResult &Result, static StringRef getFunctionSpelling(const MatchFinder::MatchResult &Result) {
const char *BindingStr) { const auto *MatchedCall = Result.Nodes.getNodeAs<CallExpr>("call");
const CallExpr *MatchedCall = cast<CallExpr>(
(Result.Nodes.getNodeAs<BinaryOperator>(BindingStr))->getLHS());
const SourceManager &SM = *Result.SourceManager; const SourceManager &SM = *Result.SourceManager;
return Lexer::getSourceText(CharSourceRange::getTokenRange( return Lexer::getSourceText(CharSourceRange::getTokenRange(
MatchedCall->getCallee()->getSourceRange()), MatchedCall->getCallee()->getSourceRange()),
@ -27,32 +25,40 @@ static StringRef getFunctionSpelling(const MatchFinder::MatchResult &Result,
} }
void PosixReturnCheck::registerMatchers(MatchFinder *Finder) { void PosixReturnCheck::registerMatchers(MatchFinder *Finder) {
const auto PosixCall =
callExpr(callee(functionDecl(
anyOf(matchesName("^::posix_"), matchesName("^::pthread_")),
unless(hasName("::posix_openpt")))))
.bind("call");
const auto ZeroIntegerLiteral = integerLiteral(equals(0));
const auto NegIntegerLiteral =
unaryOperator(hasOperatorName("-"), hasUnaryOperand(integerLiteral()));
Finder->addMatcher( Finder->addMatcher(
binaryOperator( binaryOperator(
hasOperatorName("<"), anyOf(allOf(hasOperatorName("<"), hasLHS(PosixCall),
hasLHS(callExpr(callee(functionDecl( hasRHS(ZeroIntegerLiteral)),
anyOf(matchesName("^::posix_"), matchesName("^::pthread_")), allOf(hasOperatorName(">"), hasLHS(ZeroIntegerLiteral),
unless(hasName("::posix_openpt")))))), hasRHS(PosixCall))))
hasRHS(integerLiteral(equals(0))))
.bind("ltzop"), .bind("ltzop"),
this); this);
Finder->addMatcher( Finder->addMatcher(
binaryOperator( binaryOperator(
hasOperatorName(">="), anyOf(allOf(hasOperatorName(">="), hasLHS(PosixCall),
hasLHS(callExpr(callee(functionDecl( hasRHS(ZeroIntegerLiteral)),
anyOf(matchesName("^::posix_"), matchesName("^::pthread_")), allOf(hasOperatorName("<="), hasLHS(ZeroIntegerLiteral),
unless(hasName("::posix_openpt")))))), hasRHS(PosixCall))))
hasRHS(integerLiteral(equals(0))))
.bind("atop"), .bind("atop"),
this); this);
Finder->addMatcher(binaryOperator(hasAnyOperatorName("==", "!="),
hasOperands(PosixCall, NegIntegerLiteral))
.bind("binop"),
this);
Finder->addMatcher( Finder->addMatcher(
binaryOperator( binaryOperator(anyOf(allOf(hasAnyOperatorName("<=", "<"),
hasAnyOperatorName("==", "!=", "<=", "<"), hasLHS(PosixCall), hasRHS(NegIntegerLiteral)),
hasLHS(callExpr(callee(functionDecl( allOf(hasAnyOperatorName(">", ">="),
anyOf(matchesName("^::posix_"), matchesName("^::pthread_")), hasLHS(NegIntegerLiteral), hasRHS(PosixCall))))
unless(hasName("::posix_openpt")))))),
hasRHS(unaryOperator(hasOperatorName("-"),
hasUnaryOperand(integerLiteral()))))
.bind("binop"), .bind("binop"),
this); this);
} }
@ -61,10 +67,13 @@ void PosixReturnCheck::check(const MatchFinder::MatchResult &Result) {
if (const auto *LessThanZeroOp = if (const auto *LessThanZeroOp =
Result.Nodes.getNodeAs<BinaryOperator>("ltzop")) { Result.Nodes.getNodeAs<BinaryOperator>("ltzop")) {
SourceLocation OperatorLoc = LessThanZeroOp->getOperatorLoc(); SourceLocation OperatorLoc = LessThanZeroOp->getOperatorLoc();
StringRef NewBinOp =
LessThanZeroOp->getOpcode() == BinaryOperator::Opcode::BO_LT ? ">"
: "<";
diag(OperatorLoc, "the comparison always evaluates to false because %0 " diag(OperatorLoc, "the comparison always evaluates to false because %0 "
"always returns non-negative values") "always returns non-negative values")
<< getFunctionSpelling(Result, "ltzop") << getFunctionSpelling(Result)
<< FixItHint::CreateReplacement(OperatorLoc, Twine(">").str()); << FixItHint::CreateReplacement(OperatorLoc, NewBinOp);
return; return;
} }
if (const auto *AlwaysTrueOp = if (const auto *AlwaysTrueOp =
@ -72,12 +81,12 @@ void PosixReturnCheck::check(const MatchFinder::MatchResult &Result) {
diag(AlwaysTrueOp->getOperatorLoc(), diag(AlwaysTrueOp->getOperatorLoc(),
"the comparison always evaluates to true because %0 always returns " "the comparison always evaluates to true because %0 always returns "
"non-negative values") "non-negative values")
<< getFunctionSpelling(Result, "atop"); << getFunctionSpelling(Result);
return; return;
} }
const auto *BinOp = Result.Nodes.getNodeAs<BinaryOperator>("binop"); const auto *BinOp = Result.Nodes.getNodeAs<BinaryOperator>("binop");
diag(BinOp->getOperatorLoc(), "%0 only returns non-negative values") diag(BinOp->getOperatorLoc(), "%0 only returns non-negative values")
<< getFunctionSpelling(Result, "binop"); << getFunctionSpelling(Result);
} }
} // namespace clang::tidy::bugprone } // namespace clang::tidy::bugprone

View File

@ -125,6 +125,10 @@ Changes in existing checks
<clang-tidy/checks/bugprone/forwarding-reference-overload>` check by fixing <clang-tidy/checks/bugprone/forwarding-reference-overload>` check by fixing
a crash when determining if an ``enable_if[_t]`` was found. a crash when determining if an ``enable_if[_t]`` was found.
- Improved :doc:`bugprone-posix-return
<clang-tidy/checks/bugprone/posix-return>` check to support integer literals
as LHS and posix call as RHS of comparison.
- Improved :doc:`bugprone-sizeof-expression - Improved :doc:`bugprone-sizeof-expression
<clang-tidy/checks/bugprone/sizeof-expression>` check to find suspicious <clang-tidy/checks/bugprone/sizeof-expression>` check to find suspicious
usages of ``sizeof()``, ``alignof()``, and ``offsetof()`` when adding or usages of ``sizeof()``, ``alignof()``, and ``offsetof()`` when adding or

View File

@ -74,6 +74,9 @@ void warningLessThanZero() {
if (pthread_yield() < 0) {} if (pthread_yield() < 0) {}
// CHECK-MESSAGES: :[[@LINE-1]]:23: warning: // CHECK-MESSAGES: :[[@LINE-1]]:23: warning:
// CHECK-FIXES: pthread_yield() > 0 // CHECK-FIXES: pthread_yield() > 0
if (0 > pthread_yield() ) {}
// CHECK-MESSAGES: :[[@LINE-1]]:9: warning:
// CHECK-FIXES: 0 < pthread_yield()
} }
@ -90,7 +93,8 @@ void warningAlwaysTrue() {
// CHECK-MESSAGES: :[[@LINE-1]]:31: warning: // CHECK-MESSAGES: :[[@LINE-1]]:31: warning:
if (pthread_yield() >= 0) {} if (pthread_yield() >= 0) {}
// CHECK-MESSAGES: :[[@LINE-1]]:23: warning: // CHECK-MESSAGES: :[[@LINE-1]]:23: warning:
if (0 <= pthread_yield()) {}
// CHECK-MESSAGES: :[[@LINE-1]]:9: warning:
} }
void warningEqualsNegative() { void warningEqualsNegative() {
@ -120,7 +124,14 @@ void warningEqualsNegative() {
// CHECK-MESSAGES: :[[@LINE-1]]:46: warning: // CHECK-MESSAGES: :[[@LINE-1]]:46: warning:
if (pthread_create(NULL, NULL, NULL, NULL) < -1) {} if (pthread_create(NULL, NULL, NULL, NULL) < -1) {}
// CHECK-MESSAGES: :[[@LINE-1]]:46: warning: // CHECK-MESSAGES: :[[@LINE-1]]:46: warning:
if (-1 == pthread_create(NULL, NULL, NULL, NULL)) {}
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning:
if (-1 != pthread_create(NULL, NULL, NULL, NULL)) {}
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning:
if (-1 >= pthread_create(NULL, NULL, NULL, NULL)) {}
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning:
if (-1 > pthread_create(NULL, NULL, NULL, NULL)) {}
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning:
} }
void WarningWithMacro() { void WarningWithMacro() {
@ -162,6 +173,16 @@ void noWarning() {
if (posix_openpt(0) < -1) {} if (posix_openpt(0) < -1) {}
if (posix_fadvise(0, 0, 0, 0) <= 0) {} if (posix_fadvise(0, 0, 0, 0) <= 0) {}
if (posix_fadvise(0, 0, 0, 0) == 1) {} if (posix_fadvise(0, 0, 0, 0) == 1) {}
if (0 > posix_openpt(0)) {}
if (0 >= posix_openpt(0)) {}
if (-1 == posix_openpt(0)) {}
if (-1 != posix_openpt(0)) {}
if (-1 >= posix_openpt(0)) {}
if (-1 > posix_openpt(0)) {}
if (posix_fadvise(0, 0, 0, 0) <= 0) {}
if (posix_fadvise(0, 0, 0, 0) == 1) {}
if (0 >= posix_fadvise(0, 0, 0, 0)) {}
if (1 == posix_fadvise(0, 0, 0, 0)) {}
} }
namespace i { namespace i {