• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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