1 //===--- PosixReturnCheck.cpp - clang-tidy---------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "PosixReturnCheck.h" 10 #include "clang/AST/ASTContext.h" 11 #include "clang/ASTMatchers/ASTMatchFinder.h" 12 #include "clang/ASTMatchers/ASTMatchers.h" 13 #include "clang/Lex/Lexer.h" 14 15 using namespace clang::ast_matchers; 16 17 namespace clang::tidy::bugprone { 18 19 static StringRef getFunctionSpelling(const MatchFinder::MatchResult &Result) { 20 const auto *MatchedCall = Result.Nodes.getNodeAs<CallExpr>("call"); 21 const SourceManager &SM = *Result.SourceManager; 22 return Lexer::getSourceText(CharSourceRange::getTokenRange( 23 MatchedCall->getCallee()->getSourceRange()), 24 SM, Result.Context->getLangOpts()); 25 } 26 27 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 37 Finder->addMatcher( 38 binaryOperator( 39 anyOf(allOf(hasOperatorName("<"), hasLHS(PosixCall), 40 hasRHS(ZeroIntegerLiteral)), 41 allOf(hasOperatorName(">"), hasLHS(ZeroIntegerLiteral), 42 hasRHS(PosixCall)))) 43 .bind("ltzop"), 44 this); 45 Finder->addMatcher( 46 binaryOperator( 47 anyOf(allOf(hasOperatorName(">="), hasLHS(PosixCall), 48 hasRHS(ZeroIntegerLiteral)), 49 allOf(hasOperatorName("<="), hasLHS(ZeroIntegerLiteral), 50 hasRHS(PosixCall)))) 51 .bind("atop"), 52 this); 53 Finder->addMatcher(binaryOperator(hasAnyOperatorName("==", "!="), 54 hasOperands(PosixCall, NegIntegerLiteral)) 55 .bind("binop"), 56 this); 57 Finder->addMatcher( 58 binaryOperator(anyOf(allOf(hasAnyOperatorName("<=", "<"), 59 hasLHS(PosixCall), hasRHS(NegIntegerLiteral)), 60 allOf(hasAnyOperatorName(">", ">="), 61 hasLHS(NegIntegerLiteral), hasRHS(PosixCall)))) 62 .bind("binop"), 63 this); 64 } 65 66 void PosixReturnCheck::check(const MatchFinder::MatchResult &Result) { 67 if (const auto *LessThanZeroOp = 68 Result.Nodes.getNodeAs<BinaryOperator>("ltzop")) { 69 SourceLocation OperatorLoc = LessThanZeroOp->getOperatorLoc(); 70 StringRef NewBinOp = 71 LessThanZeroOp->getOpcode() == BinaryOperator::Opcode::BO_LT ? ">" 72 : "<"; 73 diag(OperatorLoc, "the comparison always evaluates to false because %0 " 74 "always returns non-negative values") 75 << getFunctionSpelling(Result) 76 << FixItHint::CreateReplacement(OperatorLoc, NewBinOp); 77 return; 78 } 79 if (const auto *AlwaysTrueOp = 80 Result.Nodes.getNodeAs<BinaryOperator>("atop")) { 81 diag(AlwaysTrueOp->getOperatorLoc(), 82 "the comparison always evaluates to true because %0 always returns " 83 "non-negative values") 84 << getFunctionSpelling(Result); 85 return; 86 } 87 const auto *BinOp = Result.Nodes.getNodeAs<BinaryOperator>("binop"); 88 diag(BinOp->getOperatorLoc(), "%0 only returns non-negative values") 89 << getFunctionSpelling(Result); 90 } 91 92 } // namespace clang::tidy::bugprone 93