blob: ac38d233af9644d24eb43f3e97d60b8ac76bfce5 [file] [log] [blame]
Alexander Kornienkof5e72b02015-04-10 19:26:43 +00001//===--- SimplifyBooleanExpr.h clang-tidy -----------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_SIMPLIFY_BOOLEAN_EXPR_H
11#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_SIMPLIFY_BOOLEAN_EXPR_H
12
13#include "../ClangTidy.h"
14
15namespace clang {
16namespace tidy {
17namespace readability {
18
19/// \brief Looks for boolean expressions involving boolean constants and
20// simplifies them to use the appropriate boolean expression directly.
21///
22/// Examples:
23/// `if (b == true)` becomes `if (b)`
24/// `if (b == false)` becomes `if (!b)`
25/// `if (b && true)` becomes `if (b)`
26/// `if (b && false)` becomes `if (false)`
27/// `if (b || true)` becomes `if (true)`
28/// `if (b || false)` becomes `if (b)`
29/// `e ? true : false` becomes `e`
30/// `e ? false : true` becomes `!e`
31/// `if (true) t(); else f();` becomes `t();`
32/// `if (false) t(); else f();` becomes `f();`
Alexander Kornienkofb3e2cd2015-05-17 12:31:12 +000033/// `if (e) return true; else return false;` becomes `return e;`
34/// `if (e) return false; else return true;` becomes `return !e;`
Alexander Kornienkof5e72b02015-04-10 19:26:43 +000035/// `if (e) b = true; else b = false;` becomes `b = e;`
Alexander Kornienkofb3e2cd2015-05-17 12:31:12 +000036/// `if (e) b = false; else b = true;` becomes `b = !e;`
Alexander Kornienko6ae400d2015-07-01 12:39:40 +000037/// `if (e) return true; return false;` becomes `return e;`
38/// `if (e) return false; return true;` becomes `return !e;`
Alexander Kornienkofb3e2cd2015-05-17 12:31:12 +000039///
Alexander Kornienko6ae400d2015-07-01 12:39:40 +000040/// The resulting expression `e` is modified as follows:
41/// 1. Unnecessary parentheses around the expression are removed.
42/// 2. Negated applications of `!` are eliminated.
43/// 3. Negated applications of comparison operators are changed to use the
44/// opposite condition.
45/// 4. Implicit conversions of pointer to `bool` are replaced with explicit
46/// comparisons to `nullptr`.
47/// 5. Implicit casts to `bool` are replaced with explicit casts to `bool`.
48/// 6. Object expressions with `explicit operator bool` conversion operators
49/// are replaced with explicit casts to `bool`.
50///
51/// Examples:
52/// 1. The ternary assignment `bool b = (i < 0) ? true : false;` has redundant
53/// parentheses and becomes `bool b = i < 0;`.
54///
55/// 2. The conditional return `if (!b) return false; return true;` has an
56/// implied double negation and becomes `return b;`.
57///
58/// 3. The conditional return `if (i < 0) return false; return true;` becomes
59/// `return i >= 0;`.
60/// The conditional return `if (i != 0) return false; return true;` becomes
61/// `return i == 0;`.
62///
63/// 4. The conditional return `if (p) return true; return false;` has an
64/// implicit conversion of a pointer to `bool` and becomes
65/// `return p != nullptr;`.
66/// The ternary assignment `bool b = (i & 1) ? true : false;` has an implicit
67/// conversion of `i & 1` to `bool` and becomes
68/// `bool b = static_cast<bool>(i & 1);`.
69///
70/// 5. The conditional return `if (i & 1) return true; else return false;` has
71/// an implicit conversion of an integer quantity `i & 1` to `bool` and becomes
72/// `return static_cast<bool>(i & 1);`
73///
74/// 6. Given `struct X { explicit operator bool(); };`, and an instance `x` of
75/// `struct X`, the conditional return `if (x) return true; return false;`
76/// becomes `return static_cast<bool>(x);`
Alexander Kornienkofb3e2cd2015-05-17 12:31:12 +000077///
78/// When a conditional boolean return or assignment appears at the end of a
79/// chain of `if`, `else if` statements, the conditional statement is left
80/// unchanged unless the option `ChainedConditionalReturn` or
81/// `ChainedConditionalAssignment`, respectively, is specified as non-zero.
82/// The default value for both options is zero.
Alexander Kornienkof5e72b02015-04-10 19:26:43 +000083///
84class SimplifyBooleanExprCheck : public ClangTidyCheck {
85public:
Alexander Kornienkofb3e2cd2015-05-17 12:31:12 +000086 SimplifyBooleanExprCheck(StringRef Name, ClangTidyContext *Context);
87
88 void storeOptions(ClangTidyOptions::OptionMap &Options) override;
Alexander Kornienkof5e72b02015-04-10 19:26:43 +000089 void registerMatchers(ast_matchers::MatchFinder *Finder) override;
90 void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
91
92private:
93 void matchBoolBinOpExpr(ast_matchers::MatchFinder *Finder, bool Value,
94 StringRef OperatorName, StringRef BooleanId);
95
96 void matchExprBinOpBool(ast_matchers::MatchFinder *Finder, bool Value,
97 StringRef OperatorName, StringRef BooleanId);
98
99 void matchBoolCompOpExpr(ast_matchers::MatchFinder *Finder, bool Value,
100 StringRef OperatorName, StringRef BooleanId);
101
102 void matchExprCompOpBool(ast_matchers::MatchFinder *Finder, bool Value,
103 StringRef OperatorName, StringRef BooleanId);
104
105 void matchBoolCondition(ast_matchers::MatchFinder *Finder, bool Value,
106 StringRef BooleanId);
107
108 void matchTernaryResult(ast_matchers::MatchFinder *Finder, bool Value,
109 StringRef TernaryId);
110
111 void matchIfReturnsBool(ast_matchers::MatchFinder *Finder, bool Value,
112 StringRef Id);
113
114 void matchIfAssignsBool(ast_matchers::MatchFinder *Finder, bool Value,
115 StringRef Id);
116
Alexander Kornienko6ae400d2015-07-01 12:39:40 +0000117 void matchCompoundIfReturnsBool(ast_matchers::MatchFinder *Finder, bool Value,
118 StringRef Id);
119
Alexander Kornienkof5e72b02015-04-10 19:26:43 +0000120 void
121 replaceWithExpression(const ast_matchers::MatchFinder::MatchResult &Result,
122 const CXXBoolLiteralExpr *BoolLiteral, bool UseLHS,
123 bool Negated = false);
124
125 void
126 replaceWithThenStatement(const ast_matchers::MatchFinder::MatchResult &Result,
127 const CXXBoolLiteralExpr *BoolLiteral);
128
129 void
130 replaceWithElseStatement(const ast_matchers::MatchFinder::MatchResult &Result,
131 const CXXBoolLiteralExpr *FalseConditionRemoved);
132
133 void
134 replaceWithCondition(const ast_matchers::MatchFinder::MatchResult &Result,
135 const ConditionalOperator *Ternary,
136 bool Negated = false);
137
138 void replaceWithReturnCondition(
139 const ast_matchers::MatchFinder::MatchResult &Result, const IfStmt *If,
140 bool Negated = false);
141
142 void
143 replaceWithAssignment(const ast_matchers::MatchFinder::MatchResult &Result,
144 const IfStmt *If, bool Negated = false);
Alexander Kornienkofb3e2cd2015-05-17 12:31:12 +0000145
Alexander Kornienko6ae400d2015-07-01 12:39:40 +0000146 void replaceCompoundReturnWithCondition(
147 const ast_matchers::MatchFinder::MatchResult &Result,
148 const CompoundStmt *Compound, bool Negated = false);
149
Alexander Kornienkofb3e2cd2015-05-17 12:31:12 +0000150 const bool ChainedConditionalReturn;
151 const bool ChainedConditionalAssignment;
Alexander Kornienkof5e72b02015-04-10 19:26:43 +0000152};
153
154} // namespace readability
155} // namespace tidy
156} // namespace clang
157
158#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_SIMPLIFY_BOOLEAN_EXPR_H