summaryrefslogtreecommitdiffstats
path: root/clang-tools-extra/clang-tidy/readability/SimplifyBooleanExprCheck.h
blob: ac38d233af9644d24eb43f3e97d60b8ac76bfce5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
//===--- SimplifyBooleanExpr.h clang-tidy -----------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_SIMPLIFY_BOOLEAN_EXPR_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_SIMPLIFY_BOOLEAN_EXPR_H

#include "../ClangTidy.h"

namespace clang {
namespace tidy {
namespace readability {

/// \brief Looks for boolean expressions involving boolean constants and
// simplifies them to use the appropriate boolean expression directly.
///
/// Examples:
/// `if (b == true)`                           becomes `if (b)`
/// `if (b == false)`                          becomes `if (!b)`
/// `if (b && true)`                           becomes `if (b)`
/// `if (b && false)`                          becomes `if (false)`
/// `if (b || true)`                           becomes `if (true)`
/// `if (b || false)`                          becomes `if (b)`
/// `e ? true : false`                         becomes `e`
/// `e ? false : true`                         becomes `!e`
/// `if (true) t(); else f();`                 becomes `t();`
/// `if (false) t(); else f();`                becomes `f();`
/// `if (e) return true; else return false;`   becomes `return e;`
/// `if (e) return false; else return true;`   becomes `return !e;`
/// `if (e) b = true; else b = false;`         becomes `b = e;`
/// `if (e) b = false; else b = true;`         becomes `b = !e;`
/// `if (e) return true; return false;`        becomes `return e;`
/// `if (e) return false; return true;`        becomes `return !e;`
///
/// The resulting expression `e` is modified as follows:
/// 1. Unnecessary parentheses around the expression are removed.
/// 2. Negated applications of `!` are eliminated.
/// 3. Negated applications of comparison operators are changed to use the
///    opposite condition.
/// 4. Implicit conversions of pointer to `bool` are replaced with explicit
///    comparisons to `nullptr`.
/// 5. Implicit casts to `bool` are replaced with explicit casts to `bool`.
/// 6. Object expressions with `explicit operator bool` conversion operators
///    are replaced with explicit casts to `bool`.
///
/// Examples:
/// 1. The ternary assignment `bool b = (i < 0) ? true : false;` has redundant
/// parentheses and becomes `bool b = i < 0;`.
///
/// 2. The conditional return `if (!b) return false; return true;` has an
/// implied double negation and becomes `return b;`.
///
/// 3. The conditional return `if (i < 0) return false; return true;` becomes
/// `return i >= 0;`.
/// The conditional return `if (i != 0) return false; return true;` becomes
/// `return i == 0;`.
///
/// 4. The conditional return `if (p) return true; return false;` has an
/// implicit conversion of a pointer to `bool` and becomes
/// `return p != nullptr;`.
/// The ternary assignment `bool b = (i & 1) ? true : false;` has an implicit
/// conversion of `i & 1` to `bool` and becomes
/// `bool b = static_cast<bool>(i & 1);`.
///
/// 5. The conditional return `if (i & 1) return true; else return false;` has
/// an implicit conversion of an integer quantity `i & 1` to `bool` and becomes
/// `return static_cast<bool>(i & 1);`
///
/// 6. Given `struct X { explicit operator bool(); };`, and an instance `x` of
/// `struct X`, the conditional return `if (x) return true; return false;`
/// becomes `return static_cast<bool>(x);`
///
/// When a conditional boolean return or assignment appears at the end of a
/// chain of `if`, `else if` statements, the conditional statement is left
/// unchanged unless the option `ChainedConditionalReturn` or
/// `ChainedConditionalAssignment`, respectively, is specified as non-zero.
/// The default value for both options is zero.
///
class SimplifyBooleanExprCheck : public ClangTidyCheck {
public:
  SimplifyBooleanExprCheck(StringRef Name, ClangTidyContext *Context);

  void storeOptions(ClangTidyOptions::OptionMap &Options) override;
  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;

private:
  void matchBoolBinOpExpr(ast_matchers::MatchFinder *Finder, bool Value,
                          StringRef OperatorName, StringRef BooleanId);

  void matchExprBinOpBool(ast_matchers::MatchFinder *Finder, bool Value,
                          StringRef OperatorName, StringRef BooleanId);

  void matchBoolCompOpExpr(ast_matchers::MatchFinder *Finder, bool Value,
                           StringRef OperatorName, StringRef BooleanId);

  void matchExprCompOpBool(ast_matchers::MatchFinder *Finder, bool Value,
                           StringRef OperatorName, StringRef BooleanId);

  void matchBoolCondition(ast_matchers::MatchFinder *Finder, bool Value,
                          StringRef BooleanId);

  void matchTernaryResult(ast_matchers::MatchFinder *Finder, bool Value,
                          StringRef TernaryId);

  void matchIfReturnsBool(ast_matchers::MatchFinder *Finder, bool Value,
                          StringRef Id);

  void matchIfAssignsBool(ast_matchers::MatchFinder *Finder, bool Value,
                          StringRef Id);

  void matchCompoundIfReturnsBool(ast_matchers::MatchFinder *Finder, bool Value,
                                  StringRef Id);

  void
  replaceWithExpression(const ast_matchers::MatchFinder::MatchResult &Result,
                        const CXXBoolLiteralExpr *BoolLiteral, bool UseLHS,
                        bool Negated = false);

  void
  replaceWithThenStatement(const ast_matchers::MatchFinder::MatchResult &Result,
                           const CXXBoolLiteralExpr *BoolLiteral);

  void
  replaceWithElseStatement(const ast_matchers::MatchFinder::MatchResult &Result,
                           const CXXBoolLiteralExpr *FalseConditionRemoved);

  void
  replaceWithCondition(const ast_matchers::MatchFinder::MatchResult &Result,
                       const ConditionalOperator *Ternary,
                       bool Negated = false);

  void replaceWithReturnCondition(
      const ast_matchers::MatchFinder::MatchResult &Result, const IfStmt *If,
      bool Negated = false);

  void
  replaceWithAssignment(const ast_matchers::MatchFinder::MatchResult &Result,
                        const IfStmt *If, bool Negated = false);

  void replaceCompoundReturnWithCondition(
      const ast_matchers::MatchFinder::MatchResult &Result,
      const CompoundStmt *Compound, bool Negated = false);

  const bool ChainedConditionalReturn;
  const bool ChainedConditionalAssignment;
};

} // namespace readability
} // namespace tidy
} // namespace clang

#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_SIMPLIFY_BOOLEAN_EXPR_H
OpenPOWER on IntegriCloud