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 "../utils/Matchers.h"
11 #include "clang/AST/ASTContext.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 #include "clang/Lex/Lexer.h"
14
15 using namespace clang::ast_matchers;
16
17 namespace clang {
18 namespace tidy {
19 namespace bugprone {
20
getFunctionSpelling(const MatchFinder::MatchResult & Result,const char * BindingStr)21 static StringRef getFunctionSpelling(const MatchFinder::MatchResult &Result,
22 const char *BindingStr) {
23 const CallExpr *MatchedCall = cast<CallExpr>(
24 (Result.Nodes.getNodeAs<BinaryOperator>(BindingStr))->getLHS());
25 const SourceManager &SM = *Result.SourceManager;
26 return Lexer::getSourceText(CharSourceRange::getTokenRange(
27 MatchedCall->getCallee()->getSourceRange()),
28 SM, Result.Context->getLangOpts());
29 }
30
registerMatchers(MatchFinder * Finder)31 void PosixReturnCheck::registerMatchers(MatchFinder *Finder) {
32 Finder->addMatcher(
33 binaryOperator(
34 hasOperatorName("<"),
35 hasLHS(callExpr(callee(functionDecl(
36 anyOf(matchesName("^::posix_"), matchesName("^::pthread_")),
37 unless(hasName("::posix_openpt")))))),
38 hasRHS(integerLiteral(equals(0))))
39 .bind("ltzop"),
40 this);
41 Finder->addMatcher(
42 binaryOperator(
43 hasOperatorName(">="),
44 hasLHS(callExpr(callee(functionDecl(
45 anyOf(matchesName("^::posix_"), matchesName("^::pthread_")),
46 unless(hasName("::posix_openpt")))))),
47 hasRHS(integerLiteral(equals(0))))
48 .bind("atop"),
49 this);
50 Finder->addMatcher(
51 binaryOperator(
52 hasAnyOperatorName("==", "!=", "<=", "<"),
53 hasLHS(callExpr(callee(functionDecl(
54 anyOf(matchesName("^::posix_"), matchesName("^::pthread_")),
55 unless(hasName("::posix_openpt")))))),
56 hasRHS(unaryOperator(hasOperatorName("-"),
57 hasUnaryOperand(integerLiteral()))))
58 .bind("binop"),
59 this);
60 }
61
check(const MatchFinder::MatchResult & Result)62 void PosixReturnCheck::check(const MatchFinder::MatchResult &Result) {
63 if (const auto *LessThanZeroOp =
64 Result.Nodes.getNodeAs<BinaryOperator>("ltzop")) {
65 SourceLocation OperatorLoc = LessThanZeroOp->getOperatorLoc();
66 diag(OperatorLoc, "the comparison always evaluates to false because %0 "
67 "always returns non-negative values")
68 << getFunctionSpelling(Result, "ltzop")
69 << FixItHint::CreateReplacement(OperatorLoc, Twine(">").str());
70 return;
71 }
72 if (const auto *AlwaysTrueOp =
73 Result.Nodes.getNodeAs<BinaryOperator>("atop")) {
74 diag(AlwaysTrueOp->getOperatorLoc(),
75 "the comparison always evaluates to true because %0 always returns "
76 "non-negative values")
77 << getFunctionSpelling(Result, "atop");
78 return;
79 }
80 const auto *BinOp = Result.Nodes.getNodeAs<BinaryOperator>("binop");
81 diag(BinOp->getOperatorLoc(), "%0 only returns non-negative values")
82 << getFunctionSpelling(Result, "binop");
83 }
84
85 } // namespace bugprone
86 } // namespace tidy
87 } // namespace clang
88