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>(ID: "call" ); |
21 | const SourceManager &SM = *Result.SourceManager; |
22 | return Lexer::getSourceText(Range: CharSourceRange::getTokenRange( |
23 | MatchedCall->getCallee()->getSourceRange()), |
24 | SM, LangOpts: Result.Context->getLangOpts()); |
25 | } |
26 | |
27 | void PosixReturnCheck::registerMatchers(MatchFinder *Finder) { |
28 | const auto PosixCall = |
29 | callExpr(callee(InnerMatcher: functionDecl( |
30 | anyOf(matchesName(RegExp: "^::posix_" ), matchesName(RegExp: "^::pthread_" )), |
31 | unless(hasName(Name: "::posix_openpt" ))))) |
32 | .bind(ID: "call" ); |
33 | const auto ZeroIntegerLiteral = integerLiteral(equals(Value: 0)); |
34 | const auto NegIntegerLiteral = |
35 | unaryOperator(hasOperatorName(Name: "-" ), hasUnaryOperand(InnerMatcher: integerLiteral())); |
36 | |
37 | Finder->addMatcher( |
38 | NodeMatch: binaryOperator( |
39 | anyOf(allOf(hasOperatorName(Name: "<" ), hasLHS(InnerMatcher: PosixCall), |
40 | hasRHS(InnerMatcher: ZeroIntegerLiteral)), |
41 | allOf(hasOperatorName(Name: ">" ), hasLHS(InnerMatcher: ZeroIntegerLiteral), |
42 | hasRHS(InnerMatcher: PosixCall)))) |
43 | .bind(ID: "ltzop" ), |
44 | Action: this); |
45 | Finder->addMatcher( |
46 | NodeMatch: binaryOperator( |
47 | anyOf(allOf(hasOperatorName(Name: ">=" ), hasLHS(InnerMatcher: PosixCall), |
48 | hasRHS(InnerMatcher: ZeroIntegerLiteral)), |
49 | allOf(hasOperatorName(Name: "<=" ), hasLHS(InnerMatcher: ZeroIntegerLiteral), |
50 | hasRHS(InnerMatcher: PosixCall)))) |
51 | .bind(ID: "atop" ), |
52 | Action: this); |
53 | Finder->addMatcher(NodeMatch: binaryOperator(hasAnyOperatorName("==" , "!=" ), |
54 | hasOperands(Matcher1: PosixCall, Matcher2: NegIntegerLiteral)) |
55 | .bind(ID: "binop" ), |
56 | Action: this); |
57 | Finder->addMatcher( |
58 | NodeMatch: binaryOperator(anyOf(allOf(hasAnyOperatorName("<=" , "<" ), |
59 | hasLHS(InnerMatcher: PosixCall), hasRHS(InnerMatcher: NegIntegerLiteral)), |
60 | allOf(hasAnyOperatorName(">" , ">=" ), |
61 | hasLHS(InnerMatcher: NegIntegerLiteral), hasRHS(InnerMatcher: PosixCall)))) |
62 | .bind(ID: "binop" ), |
63 | Action: this); |
64 | } |
65 | |
66 | void PosixReturnCheck::check(const MatchFinder::MatchResult &Result) { |
67 | if (const auto *LessThanZeroOp = |
68 | Result.Nodes.getNodeAs<BinaryOperator>(ID: "ltzop" )) { |
69 | SourceLocation OperatorLoc = LessThanZeroOp->getOperatorLoc(); |
70 | StringRef NewBinOp = |
71 | LessThanZeroOp->getOpcode() == BinaryOperator::Opcode::BO_LT ? ">" |
72 | : "<" ; |
73 | diag(Loc: OperatorLoc, Description: "the comparison always evaluates to false because %0 " |
74 | "always returns non-negative values" ) |
75 | << getFunctionSpelling(Result) |
76 | << FixItHint::CreateReplacement(RemoveRange: OperatorLoc, Code: NewBinOp); |
77 | return; |
78 | } |
79 | if (const auto *AlwaysTrueOp = |
80 | Result.Nodes.getNodeAs<BinaryOperator>(ID: "atop" )) { |
81 | diag(Loc: AlwaysTrueOp->getOperatorLoc(), |
82 | Description: "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>(ID: "binop" ); |
88 | diag(Loc: BinOp->getOperatorLoc(), Description: "%0 only returns non-negative values" ) |
89 | << getFunctionSpelling(Result); |
90 | } |
91 | |
92 | } // namespace clang::tidy::bugprone |
93 | |