blob: b3bd51653b7143d1b043df93023ec5044314006a [file] [log] [blame]
Etienne Bergeronbda187d2016-04-26 17:30:30 +00001//===--- RedundantExpressionCheck.cpp - clang-tidy-------------------------===//
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#include "RedundantExpressionCheck.h"
11#include "../utils/Matchers.h"
Etienne Bergeronc87599f2016-05-12 04:32:47 +000012#include "../utils/OptionsUtils.h"
Etienne Bergeronbda187d2016-04-26 17:30:30 +000013#include "clang/AST/ASTContext.h"
14#include "clang/ASTMatchers/ASTMatchFinder.h"
Eugene Zelenko90c117a2016-11-01 18:33:50 +000015#include "clang/Basic/LLVM.h"
16#include "clang/Basic/SourceLocation.h"
17#include "clang/Basic/SourceManager.h"
Etienne Bergeronc87599f2016-05-12 04:32:47 +000018#include "clang/Lex/Lexer.h"
Eugene Zelenko90c117a2016-11-01 18:33:50 +000019#include "llvm/ADT/APInt.h"
20#include "llvm/ADT/APSInt.h"
21#include "llvm/ADT/FoldingSet.h"
22#include "llvm/Support/Casting.h"
23#include <algorithm>
24#include <cassert>
25#include <cstdint>
Eugene Zelenko90c117a2016-11-01 18:33:50 +000026#include <string>
27#include <vector>
Etienne Bergeronbda187d2016-04-26 17:30:30 +000028
29using namespace clang::ast_matchers;
Etienne Bergeron00639bc2016-07-07 04:03:05 +000030using namespace clang::tidy::matchers;
Etienne Bergeronbda187d2016-04-26 17:30:30 +000031
32namespace clang {
33namespace tidy {
34namespace misc {
35
Etienne Bergeron00639bc2016-07-07 04:03:05 +000036namespace {
37using llvm::APSInt;
38} // namespace
39
Gabor Horvathec87e172017-11-07 13:17:58 +000040static const llvm::StringSet<> KnownBannedMacroNames = {"EAGAIN", "EWOULDBLOCK",
41 "SIGCLD", "SIGCHLD"};
Etienne Bergeronc87599f2016-05-12 04:32:47 +000042
Etienne Bergeron00639bc2016-07-07 04:03:05 +000043static bool incrementWithoutOverflow(const APSInt &Value, APSInt &Result) {
44 Result = Value;
45 ++Result;
46 return Value < Result;
47}
48
Etienne Bergeronc87599f2016-05-12 04:32:47 +000049static bool areEquivalentNameSpecifier(const NestedNameSpecifier *Left,
50 const NestedNameSpecifier *Right) {
51 llvm::FoldingSetNodeID LeftID, RightID;
52 Left->Profile(LeftID);
53 Right->Profile(RightID);
54 return LeftID == RightID;
55}
56
57static bool areEquivalentExpr(const Expr *Left, const Expr *Right) {
Etienne Bergeronbda187d2016-04-26 17:30:30 +000058 if (!Left || !Right)
59 return !Left && !Right;
60
61 Left = Left->IgnoreParens();
62 Right = Right->IgnoreParens();
63
64 // Compare classes.
65 if (Left->getStmtClass() != Right->getStmtClass())
66 return false;
67
68 // Compare children.
69 Expr::const_child_iterator LeftIter = Left->child_begin();
70 Expr::const_child_iterator RightIter = Right->child_begin();
71 while (LeftIter != Left->child_end() && RightIter != Right->child_end()) {
Etienne Bergeronc87599f2016-05-12 04:32:47 +000072 if (!areEquivalentExpr(dyn_cast<Expr>(*LeftIter),
73 dyn_cast<Expr>(*RightIter)))
Etienne Bergeronbda187d2016-04-26 17:30:30 +000074 return false;
75 ++LeftIter;
76 ++RightIter;
77 }
78 if (LeftIter != Left->child_end() || RightIter != Right->child_end())
79 return false;
80
81 // Perform extra checks.
82 switch (Left->getStmtClass()) {
83 default:
84 return false;
85
86 case Stmt::CharacterLiteralClass:
87 return cast<CharacterLiteral>(Left)->getValue() ==
88 cast<CharacterLiteral>(Right)->getValue();
89 case Stmt::IntegerLiteralClass: {
90 llvm::APInt LeftLit = cast<IntegerLiteral>(Left)->getValue();
91 llvm::APInt RightLit = cast<IntegerLiteral>(Right)->getValue();
Etienne Bergeronc87599f2016-05-12 04:32:47 +000092 return LeftLit.getBitWidth() == RightLit.getBitWidth() &&
93 LeftLit == RightLit;
Etienne Bergeronbda187d2016-04-26 17:30:30 +000094 }
95 case Stmt::FloatingLiteralClass:
96 return cast<FloatingLiteral>(Left)->getValue().bitwiseIsEqual(
97 cast<FloatingLiteral>(Right)->getValue());
98 case Stmt::StringLiteralClass:
99 return cast<StringLiteral>(Left)->getBytes() ==
100 cast<StringLiteral>(Right)->getBytes();
Gabor Horvath250c40d2017-11-27 15:05:24 +0000101 case Stmt::CXXOperatorCallExprClass:
102 return cast<CXXOperatorCallExpr>(Left)->getOperator() ==
103 cast<CXXOperatorCallExpr>(Right)->getOperator();
Etienne Bergeronc87599f2016-05-12 04:32:47 +0000104 case Stmt::DependentScopeDeclRefExprClass:
105 if (cast<DependentScopeDeclRefExpr>(Left)->getDeclName() !=
106 cast<DependentScopeDeclRefExpr>(Right)->getDeclName())
107 return false;
108 return areEquivalentNameSpecifier(
109 cast<DependentScopeDeclRefExpr>(Left)->getQualifier(),
110 cast<DependentScopeDeclRefExpr>(Right)->getQualifier());
Etienne Bergeronbda187d2016-04-26 17:30:30 +0000111 case Stmt::DeclRefExprClass:
112 return cast<DeclRefExpr>(Left)->getDecl() ==
113 cast<DeclRefExpr>(Right)->getDecl();
114 case Stmt::MemberExprClass:
115 return cast<MemberExpr>(Left)->getMemberDecl() ==
116 cast<MemberExpr>(Right)->getMemberDecl();
Gabor Horvathec87e172017-11-07 13:17:58 +0000117 case Stmt::CXXFunctionalCastExprClass:
Etienne Bergeronbda187d2016-04-26 17:30:30 +0000118 case Stmt::CStyleCastExprClass:
Gabor Horvathec87e172017-11-07 13:17:58 +0000119 return cast<ExplicitCastExpr>(Left)->getTypeAsWritten() ==
120 cast<ExplicitCastExpr>(Right)->getTypeAsWritten();
Etienne Bergeronbda187d2016-04-26 17:30:30 +0000121 case Stmt::CallExprClass:
122 case Stmt::ImplicitCastExprClass:
123 case Stmt::ArraySubscriptExprClass:
124 return true;
Etienne Bergeronbda187d2016-04-26 17:30:30 +0000125 case Stmt::UnaryOperatorClass:
126 if (cast<UnaryOperator>(Left)->isIncrementDecrementOp())
127 return false;
128 return cast<UnaryOperator>(Left)->getOpcode() ==
129 cast<UnaryOperator>(Right)->getOpcode();
130 case Stmt::BinaryOperatorClass:
131 return cast<BinaryOperator>(Left)->getOpcode() ==
132 cast<BinaryOperator>(Right)->getOpcode();
133 }
134}
135
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000136// For a given expression 'x', returns whether the ranges covered by the
137// relational operators are equivalent (i.e. x <= 4 is equivalent to x < 5).
138static bool areEquivalentRanges(BinaryOperatorKind OpcodeLHS,
139 const APSInt &ValueLHS,
140 BinaryOperatorKind OpcodeRHS,
141 const APSInt &ValueRHS) {
142 assert(APSInt::compareValues(ValueLHS, ValueRHS) <= 0 &&
143 "Values must be ordered");
144 // Handle the case where constants are the same: x <= 4 <==> x <= 4.
145 if (APSInt::compareValues(ValueLHS, ValueRHS) == 0)
146 return OpcodeLHS == OpcodeRHS;
147
148 // Handle the case where constants are off by one: x <= 4 <==> x < 5.
149 APSInt ValueLHS_plus1;
150 return ((OpcodeLHS == BO_LE && OpcodeRHS == BO_LT) ||
151 (OpcodeLHS == BO_GT && OpcodeRHS == BO_GE)) &&
152 incrementWithoutOverflow(ValueLHS, ValueLHS_plus1) &&
153 APSInt::compareValues(ValueLHS_plus1, ValueRHS) == 0;
154}
155
156// For a given expression 'x', returns whether the ranges covered by the
157// relational operators are fully disjoint (i.e. x < 4 and x > 7).
158static bool areExclusiveRanges(BinaryOperatorKind OpcodeLHS,
159 const APSInt &ValueLHS,
160 BinaryOperatorKind OpcodeRHS,
161 const APSInt &ValueRHS) {
162 assert(APSInt::compareValues(ValueLHS, ValueRHS) <= 0 &&
163 "Values must be ordered");
164
165 // Handle cases where the constants are the same.
166 if (APSInt::compareValues(ValueLHS, ValueRHS) == 0) {
167 switch (OpcodeLHS) {
168 case BO_EQ:
169 return OpcodeRHS == BO_NE || OpcodeRHS == BO_GT || OpcodeRHS == BO_LT;
170 case BO_NE:
171 return OpcodeRHS == BO_EQ;
172 case BO_LE:
173 return OpcodeRHS == BO_GT;
174 case BO_GE:
175 return OpcodeRHS == BO_LT;
176 case BO_LT:
177 return OpcodeRHS == BO_EQ || OpcodeRHS == BO_GT || OpcodeRHS == BO_GE;
178 case BO_GT:
179 return OpcodeRHS == BO_EQ || OpcodeRHS == BO_LT || OpcodeRHS == BO_LE;
180 default:
181 return false;
182 }
183 }
184
185 // Handle cases where the constants are different.
Eugene Zelenko90c117a2016-11-01 18:33:50 +0000186 if ((OpcodeLHS == BO_EQ || OpcodeLHS == BO_LT || OpcodeLHS == BO_LE) &&
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000187 (OpcodeRHS == BO_EQ || OpcodeRHS == BO_GT || OpcodeRHS == BO_GE))
188 return true;
189
190 // Handle the case where constants are off by one: x > 5 && x < 6.
191 APSInt ValueLHS_plus1;
192 if (OpcodeLHS == BO_GT && OpcodeRHS == BO_LT &&
193 incrementWithoutOverflow(ValueLHS, ValueLHS_plus1) &&
194 APSInt::compareValues(ValueLHS_plus1, ValueRHS) == 0)
195 return true;
196
197 return false;
198}
199
200// Returns whether the ranges covered by the union of both relational
201// expressions covers the whole domain (i.e. x < 10 and x > 0).
202static bool rangesFullyCoverDomain(BinaryOperatorKind OpcodeLHS,
203 const APSInt &ValueLHS,
204 BinaryOperatorKind OpcodeRHS,
205 const APSInt &ValueRHS) {
206 assert(APSInt::compareValues(ValueLHS, ValueRHS) <= 0 &&
207 "Values must be ordered");
208
209 // Handle cases where the constants are the same: x < 5 || x >= 5.
210 if (APSInt::compareValues(ValueLHS, ValueRHS) == 0) {
211 switch (OpcodeLHS) {
212 case BO_EQ:
213 return OpcodeRHS == BO_NE;
214 case BO_NE:
215 return OpcodeRHS == BO_EQ;
216 case BO_LE:
217 return OpcodeRHS == BO_GT || OpcodeRHS == BO_GE;
218 case BO_LT:
219 return OpcodeRHS == BO_GE;
220 case BO_GE:
221 return OpcodeRHS == BO_LT || OpcodeRHS == BO_LE;
222 case BO_GT:
223 return OpcodeRHS == BO_LE;
224 default:
225 return false;
226 }
227 }
228
229 // Handle the case where constants are off by one: x <= 4 || x >= 5.
230 APSInt ValueLHS_plus1;
231 if (OpcodeLHS == BO_LE && OpcodeRHS == BO_GE &&
232 incrementWithoutOverflow(ValueLHS, ValueLHS_plus1) &&
233 APSInt::compareValues(ValueLHS_plus1, ValueRHS) == 0)
234 return true;
235
236 // Handle cases where the constants are different: x > 4 || x <= 7.
237 if ((OpcodeLHS == BO_GT || OpcodeLHS == BO_GE) &&
238 (OpcodeRHS == BO_LT || OpcodeRHS == BO_LE))
239 return true;
240
Alexander Kornienkoc3acd2e2017-03-23 15:13:54 +0000241 // Handle cases where constants are different but both ops are !=, like:
242 // x != 5 || x != 10
243 if (OpcodeLHS == BO_NE && OpcodeRHS == BO_NE)
244 return true;
245
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000246 return false;
247}
248
249static bool rangeSubsumesRange(BinaryOperatorKind OpcodeLHS,
250 const APSInt &ValueLHS,
251 BinaryOperatorKind OpcodeRHS,
252 const APSInt &ValueRHS) {
253 int Comparison = APSInt::compareValues(ValueLHS, ValueRHS);
254 switch (OpcodeLHS) {
255 case BO_EQ:
256 return OpcodeRHS == BO_EQ && Comparison == 0;
257 case BO_NE:
258 return (OpcodeRHS == BO_NE && Comparison == 0) ||
259 (OpcodeRHS == BO_EQ && Comparison != 0) ||
260 (OpcodeRHS == BO_LT && Comparison >= 0) ||
261 (OpcodeRHS == BO_LE && Comparison > 0) ||
262 (OpcodeRHS == BO_GT && Comparison <= 0) ||
263 (OpcodeRHS == BO_GE && Comparison < 0);
264
265 case BO_LT:
266 return ((OpcodeRHS == BO_LT && Comparison >= 0) ||
267 (OpcodeRHS == BO_LE && Comparison > 0) ||
268 (OpcodeRHS == BO_EQ && Comparison > 0));
269 case BO_GT:
270 return ((OpcodeRHS == BO_GT && Comparison <= 0) ||
271 (OpcodeRHS == BO_GE && Comparison < 0) ||
272 (OpcodeRHS == BO_EQ && Comparison < 0));
273 case BO_LE:
274 return (OpcodeRHS == BO_LT || OpcodeRHS == BO_LE || OpcodeRHS == BO_EQ) &&
275 Comparison >= 0;
276 case BO_GE:
277 return (OpcodeRHS == BO_GT || OpcodeRHS == BO_GE || OpcodeRHS == BO_EQ) &&
278 Comparison <= 0;
279 default:
280 return false;
281 }
282}
283
Gabor Horvathec87e172017-11-07 13:17:58 +0000284static void transformSubToCanonicalAddExpr(BinaryOperatorKind &Opcode,
285 APSInt &Value) {
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000286 if (Opcode == BO_Sub) {
287 Opcode = BO_Add;
288 Value = -Value;
289 }
290}
291
292AST_MATCHER(Expr, isIntegerConstantExpr) {
293 if (Node.isInstantiationDependent())
294 return false;
295 return Node.isIntegerConstantExpr(Finder->getASTContext());
296}
297
Gabor Horvathec87e172017-11-07 13:17:58 +0000298AST_MATCHER(BinaryOperator, operandsAreEquivalent) {
299 return areEquivalentExpr(Node.getLHS(), Node.getRHS());
300}
301
302AST_MATCHER(ConditionalOperator, expressionsAreEquivalent) {
303 return areEquivalentExpr(Node.getTrueExpr(), Node.getFalseExpr());
304}
305
306AST_MATCHER(CallExpr, parametersAreEquivalent) {
307 return Node.getNumArgs() == 2 &&
308 areEquivalentExpr(Node.getArg(0), Node.getArg(1));
309}
310
311AST_MATCHER(BinaryOperator, binaryOperatorIsInMacro) {
312 return Node.getOperatorLoc().isMacroID();
313}
314
315AST_MATCHER(ConditionalOperator, conditionalOperatorIsInMacro) {
316 return Node.getQuestionLoc().isMacroID() || Node.getColonLoc().isMacroID();
317}
318
319AST_MATCHER(Expr, isMacro) { return Node.getExprLoc().isMacroID(); }
320
321AST_MATCHER_P(Expr, expandedByMacro, llvm::StringSet<>, Names) {
322 const SourceManager &SM = Finder->getASTContext().getSourceManager();
323 const LangOptions &LO = Finder->getASTContext().getLangOpts();
324 SourceLocation Loc = Node.getExprLoc();
325 while (Loc.isMacroID()) {
326 StringRef MacroName = Lexer::getImmediateMacroName(Loc, SM, LO);
327 if (Names.count(MacroName))
328 return true;
329 Loc = SM.getImmediateMacroCallerLoc(Loc);
330 }
331 return false;
332}
333
334// Returns a matcher for integer constant expressions.
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000335static ast_matchers::internal::Matcher<Expr>
336matchIntegerConstantExpr(StringRef Id) {
337 std::string CstId = (Id + "-const").str();
338 return expr(isIntegerConstantExpr()).bind(CstId);
339}
340
Gabor Horvathec87e172017-11-07 13:17:58 +0000341// Retrieves the integer expression matched by 'matchIntegerConstantExpr' with
342// name 'Id' and stores it into 'ConstExpr', the value of the expression is
343// stored into `Value`.
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000344static bool retrieveIntegerConstantExpr(const MatchFinder::MatchResult &Result,
Gabor Horvathec87e172017-11-07 13:17:58 +0000345 StringRef Id, APSInt &Value,
346 const Expr *&ConstExpr) {
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000347 std::string CstId = (Id + "-const").str();
Gabor Horvathec87e172017-11-07 13:17:58 +0000348 ConstExpr = Result.Nodes.getNodeAs<Expr>(CstId);
349 return ConstExpr && ConstExpr->isIntegerConstantExpr(Value, *Result.Context);
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000350}
351
Gabor Horvathec87e172017-11-07 13:17:58 +0000352// Overloaded `retrieveIntegerConstantExpr` for compatibility.
353static bool retrieveIntegerConstantExpr(const MatchFinder::MatchResult &Result,
354 StringRef Id, APSInt &Value) {
355 const Expr *ConstExpr = nullptr;
356 return retrieveIntegerConstantExpr(Result, Id, Value, ConstExpr);
357}
358
359// Returns a matcher for symbolic expressions (matches every expression except
360// ingeter constant expressions).
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000361static ast_matchers::internal::Matcher<Expr> matchSymbolicExpr(StringRef Id) {
362 std::string SymId = (Id + "-sym").str();
363 return ignoringParenImpCasts(
364 expr(unless(isIntegerConstantExpr())).bind(SymId));
365}
366
Gabor Horvathec87e172017-11-07 13:17:58 +0000367// Retrieves the expression matched by 'matchSymbolicExpr' with name 'Id' and
368// stores it into 'SymExpr'.
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000369static bool retrieveSymbolicExpr(const MatchFinder::MatchResult &Result,
370 StringRef Id, const Expr *&SymExpr) {
371 std::string SymId = (Id + "-sym").str();
372 if (const auto *Node = Result.Nodes.getNodeAs<Expr>(SymId)) {
373 SymExpr = Node;
374 return true;
375 }
376 return false;
377}
378
379// Match a binary operator between a symbolic expression and an integer constant
380// expression.
381static ast_matchers::internal::Matcher<Expr>
382matchBinOpIntegerConstantExpr(StringRef Id) {
383 const auto BinOpCstExpr =
384 expr(
385 anyOf(binaryOperator(anyOf(hasOperatorName("+"), hasOperatorName("|"),
386 hasOperatorName("&")),
387 hasEitherOperand(matchSymbolicExpr(Id)),
388 hasEitherOperand(matchIntegerConstantExpr(Id))),
389 binaryOperator(hasOperatorName("-"),
390 hasLHS(matchSymbolicExpr(Id)),
391 hasRHS(matchIntegerConstantExpr(Id)))))
392 .bind(Id);
393 return ignoringParenImpCasts(BinOpCstExpr);
394}
395
Gabor Horvathec87e172017-11-07 13:17:58 +0000396// Retrieves sub-expressions matched by 'matchBinOpIntegerConstantExpr' with
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000397// name 'Id'.
398static bool
399retrieveBinOpIntegerConstantExpr(const MatchFinder::MatchResult &Result,
400 StringRef Id, BinaryOperatorKind &Opcode,
401 const Expr *&Symbol, APSInt &Value) {
402 if (const auto *BinExpr = Result.Nodes.getNodeAs<BinaryOperator>(Id)) {
403 Opcode = BinExpr->getOpcode();
404 return retrieveSymbolicExpr(Result, Id, Symbol) &&
405 retrieveIntegerConstantExpr(Result, Id, Value);
406 }
407 return false;
408}
409
Gabor Horvathec87e172017-11-07 13:17:58 +0000410// Matches relational expressions: 'Expr <op> k' (i.e. x < 2, x != 3, 12 <= x).
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000411static ast_matchers::internal::Matcher<Expr>
412matchRelationalIntegerConstantExpr(StringRef Id) {
413 std::string CastId = (Id + "-cast").str();
414 std::string SwapId = (Id + "-swap").str();
415 std::string NegateId = (Id + "-negate").str();
Gabor Horvath250c40d2017-11-27 15:05:24 +0000416 std::string OverloadId = (Id + "-overload").str();
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000417
418 const auto RelationalExpr = ignoringParenImpCasts(binaryOperator(
419 isComparisonOperator(), expr().bind(Id),
420 anyOf(allOf(hasLHS(matchSymbolicExpr(Id)),
421 hasRHS(matchIntegerConstantExpr(Id))),
422 allOf(hasLHS(matchIntegerConstantExpr(Id)),
423 hasRHS(matchSymbolicExpr(Id)), expr().bind(SwapId)))));
424
425 // A cast can be matched as a comparator to zero. (i.e. if (x) is equivalent
426 // to if (x != 0)).
427 const auto CastExpr =
428 implicitCastExpr(hasCastKind(CK_IntegralToBoolean),
429 hasSourceExpression(matchSymbolicExpr(Id)))
430 .bind(CastId);
431
432 const auto NegateRelationalExpr =
433 unaryOperator(hasOperatorName("!"),
434 hasUnaryOperand(anyOf(CastExpr, RelationalExpr)))
435 .bind(NegateId);
436
Gabor Horvathec87e172017-11-07 13:17:58 +0000437 // Do not bind to double negation.
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000438 const auto NegateNegateRelationalExpr =
439 unaryOperator(hasOperatorName("!"),
440 hasUnaryOperand(unaryOperator(
441 hasOperatorName("!"),
442 hasUnaryOperand(anyOf(CastExpr, RelationalExpr)))));
443
Gabor Horvath250c40d2017-11-27 15:05:24 +0000444 const auto OverloadedOperatorExpr =
445 cxxOperatorCallExpr(
446 anyOf(hasOverloadedOperatorName("=="),
447 hasOverloadedOperatorName("!="), hasOverloadedOperatorName("<"),
448 hasOverloadedOperatorName("<="), hasOverloadedOperatorName(">"),
449 hasOverloadedOperatorName(">=")),
450 // Filter noisy false positives.
451 unless(isMacro()), unless(isInTemplateInstantiation()))
452 .bind(OverloadId);
453
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000454 return anyOf(RelationalExpr, CastExpr, NegateRelationalExpr,
Gabor Horvath250c40d2017-11-27 15:05:24 +0000455 NegateNegateRelationalExpr, OverloadedOperatorExpr);
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000456}
457
Gabor Horvath250c40d2017-11-27 15:05:24 +0000458// Checks whether a function param is non constant reference type, and may
459// be modified in the function.
460static bool isNonConstReferenceType(QualType ParamType) {
461 return ParamType->isReferenceType() &&
462 !ParamType.getNonReferenceType().isConstQualified();
463}
464
465// Checks whether the arguments of an overloaded operator can be modified in the
466// function.
467// For operators that take an instance and a constant as arguments, only the
468// first argument (the instance) needs to be checked, since the constant itself
469// is a temporary expression. Whether the second parameter is checked is
470// controlled by the parameter `ParamsToCheckCount`.
471static bool
472canOverloadedOperatorArgsBeModified(const FunctionDecl *OperatorDecl,
473 bool checkSecondParam) {
474 unsigned ParamCount = OperatorDecl->getNumParams();
475
476 // Overloaded operators declared inside a class have only one param.
477 // These functions must be declared const in order to not be able to modify
478 // the instance of the class they are called through.
479 if (ParamCount == 1 &&
480 !OperatorDecl->getType()->getAs<FunctionType>()->isConst())
481 return true;
482
483 if (isNonConstReferenceType(OperatorDecl->getParamDecl(0)->getType()))
484 return true;
485
486 return checkSecondParam && ParamCount == 2 &&
487 isNonConstReferenceType(OperatorDecl->getParamDecl(1)->getType());
488}
489
490// Retrieves sub-expressions matched by 'matchRelationalIntegerConstantExpr'
491// with name 'Id'.
Gabor Horvathec87e172017-11-07 13:17:58 +0000492static bool retrieveRelationalIntegerConstantExpr(
493 const MatchFinder::MatchResult &Result, StringRef Id,
494 const Expr *&OperandExpr, BinaryOperatorKind &Opcode, const Expr *&Symbol,
495 APSInt &Value, const Expr *&ConstExpr) {
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000496 std::string CastId = (Id + "-cast").str();
497 std::string SwapId = (Id + "-swap").str();
498 std::string NegateId = (Id + "-negate").str();
Gabor Horvath250c40d2017-11-27 15:05:24 +0000499 std::string OverloadId = (Id + "-overload").str();
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000500
501 if (const auto *Bin = Result.Nodes.getNodeAs<BinaryOperator>(Id)) {
502 // Operand received with explicit comparator.
503 Opcode = Bin->getOpcode();
504 OperandExpr = Bin;
Gabor Horvathec87e172017-11-07 13:17:58 +0000505
506 if (!retrieveIntegerConstantExpr(Result, Id, Value, ConstExpr))
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000507 return false;
508 } else if (const auto *Cast = Result.Nodes.getNodeAs<CastExpr>(CastId)) {
509 // Operand received with implicit comparator (cast).
510 Opcode = BO_NE;
511 OperandExpr = Cast;
Eugene Zelenko90c117a2016-11-01 18:33:50 +0000512 Value = APSInt(32, false);
Gabor Horvath250c40d2017-11-27 15:05:24 +0000513 } else if (const auto *OverloadedOperatorExpr =
514 Result.Nodes.getNodeAs<CXXOperatorCallExpr>(OverloadId)) {
515 const auto *OverloadedFunctionDecl = dyn_cast_or_null<FunctionDecl>(OverloadedOperatorExpr->getCalleeDecl());
516 if (!OverloadedFunctionDecl)
517 return false;
518
519 if (canOverloadedOperatorArgsBeModified(OverloadedFunctionDecl, false))
520 return false;
521
522 if (!OverloadedOperatorExpr->getArg(1)->isIntegerConstantExpr(
523 Value, *Result.Context))
524 return false;
525
526 Symbol = OverloadedOperatorExpr->getArg(0);
527 OperandExpr = OverloadedOperatorExpr;
528 Opcode = BinaryOperator::getOverloadedOpcode(OverloadedOperatorExpr->getOperator());
529
530 return BinaryOperator::isComparisonOp(Opcode);
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000531 } else {
532 return false;
533 }
534
535 if (!retrieveSymbolicExpr(Result, Id, Symbol))
536 return false;
537
538 if (Result.Nodes.getNodeAs<Expr>(SwapId))
539 Opcode = BinaryOperator::reverseComparisonOp(Opcode);
540 if (Result.Nodes.getNodeAs<Expr>(NegateId))
541 Opcode = BinaryOperator::negateComparisonOp(Opcode);
Gabor Horvathec87e172017-11-07 13:17:58 +0000542 return true;
543}
544
545// Checks for expressions like (X == 4) && (Y != 9)
546static bool areSidesBinaryConstExpressions(const BinaryOperator *&BinOp, const ASTContext *AstCtx) {
547 const auto *LhsBinOp = dyn_cast<BinaryOperator>(BinOp->getLHS());
548 const auto *RhsBinOp = dyn_cast<BinaryOperator>(BinOp->getRHS());
549
550 if (!LhsBinOp || !RhsBinOp)
551 return false;
552
553 if ((LhsBinOp->getLHS()->isIntegerConstantExpr(*AstCtx) ||
554 LhsBinOp->getRHS()->isIntegerConstantExpr(*AstCtx)) &&
555 (RhsBinOp->getLHS()->isIntegerConstantExpr(*AstCtx) ||
556 RhsBinOp->getRHS()->isIntegerConstantExpr(*AstCtx)))
557 return true;
558 return false;
559}
560
561// Retrieves integer constant subexpressions from binary operator expressions
562// that have two equivalent sides
563// E.g.: from (X == 5) && (X == 5) retrieves 5 and 5.
564static bool retrieveConstExprFromBothSides(const BinaryOperator *&BinOp,
565 BinaryOperatorKind &MainOpcode,
566 BinaryOperatorKind &SideOpcode,
567 const Expr *&LhsConst,
568 const Expr *&RhsConst,
569 const ASTContext *AstCtx) {
570 assert(areSidesBinaryConstExpressions(BinOp, AstCtx) &&
571 "Both sides of binary operator must be constant expressions!");
572
573 MainOpcode = BinOp->getOpcode();
574
575 const auto *BinOpLhs = cast<BinaryOperator>(BinOp->getLHS());
576 const auto *BinOpRhs = cast<BinaryOperator>(BinOp->getRHS());
577
578 LhsConst = BinOpLhs->getLHS()->isIntegerConstantExpr(*AstCtx)
579 ? BinOpLhs->getLHS()
580 : BinOpLhs->getRHS();
581 RhsConst = BinOpRhs->getLHS()->isIntegerConstantExpr(*AstCtx)
582 ? BinOpRhs->getLHS()
583 : BinOpRhs->getRHS();
584
585 if (!LhsConst || !RhsConst)
586 return false;
587
588 assert(BinOpLhs->getOpcode() == BinOpRhs->getOpcode() &&
589 "Sides of the binary operator must be equivalent expressions!");
590
591 SideOpcode = BinOpLhs->getOpcode();
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000592
593 return true;
594}
595
Gabor Horvathec87e172017-11-07 13:17:58 +0000596static bool areExprsFromDifferentMacros(const Expr *LhsExpr,
597 const Expr *RhsExpr,
598 const ASTContext *AstCtx) {
599 if (!LhsExpr || !RhsExpr)
600 return false;
601
602 SourceLocation LhsLoc = LhsExpr->getExprLoc();
603 SourceLocation RhsLoc = RhsExpr->getExprLoc();
604
605 if (!LhsLoc.isMacroID() || !RhsLoc.isMacroID())
606 return false;
607
608 const SourceManager &SM = AstCtx->getSourceManager();
609 const LangOptions &LO = AstCtx->getLangOpts();
610
611 return !(Lexer::getImmediateMacroName(LhsLoc, SM, LO) ==
612 Lexer::getImmediateMacroName(RhsLoc, SM, LO));
Etienne Bergeronbda187d2016-04-26 17:30:30 +0000613}
614
Gabor Horvath250c40d2017-11-27 15:05:24 +0000615static bool areExprsMacroAndNonMacro(const Expr *&LhsExpr,
616 const Expr *&RhsExpr) {
Gabor Horvathec87e172017-11-07 13:17:58 +0000617 if (!LhsExpr || !RhsExpr)
618 return false;
Etienne Bergeronc87599f2016-05-12 04:32:47 +0000619
Gabor Horvathec87e172017-11-07 13:17:58 +0000620 SourceLocation LhsLoc = LhsExpr->getExprLoc();
621 SourceLocation RhsLoc = RhsExpr->getExprLoc();
Etienne Bergeronc87599f2016-05-12 04:32:47 +0000622
Gabor Horvathec87e172017-11-07 13:17:58 +0000623 return LhsLoc.isMacroID() != RhsLoc.isMacroID();
Etienne Bergeronbda187d2016-04-26 17:30:30 +0000624}
625
626void RedundantExpressionCheck::registerMatchers(MatchFinder *Finder) {
627 const auto AnyLiteralExpr = ignoringParenImpCasts(
628 anyOf(cxxBoolLiteral(), characterLiteral(), integerLiteral()));
629
Gabor Horvath250c40d2017-11-27 15:05:24 +0000630 const auto BannedIntegerLiteral =
631 integerLiteral(expandedByMacro(KnownBannedMacroNames));
Etienne Bergeronc87599f2016-05-12 04:32:47 +0000632
Gabor Horvathec87e172017-11-07 13:17:58 +0000633 // Binary with equivalent operands, like (X != 2 && X != 2).
Etienne Bergeronbda187d2016-04-26 17:30:30 +0000634 Finder->addMatcher(
635 binaryOperator(anyOf(hasOperatorName("-"), hasOperatorName("/"),
636 hasOperatorName("%"), hasOperatorName("|"),
637 hasOperatorName("&"), hasOperatorName("^"),
638 matchers::isComparisonOperator(),
639 hasOperatorName("&&"), hasOperatorName("||"),
640 hasOperatorName("=")),
Etienne Bergeronc87599f2016-05-12 04:32:47 +0000641 operandsAreEquivalent(),
Etienne Bergeronbda187d2016-04-26 17:30:30 +0000642 // Filter noisy false positives.
Etienne Bergeronc87599f2016-05-12 04:32:47 +0000643 unless(isInTemplateInstantiation()),
644 unless(binaryOperatorIsInMacro()),
Etienne Bergeronbda187d2016-04-26 17:30:30 +0000645 unless(hasType(realFloatingPointType())),
646 unless(hasEitherOperand(hasType(realFloatingPointType()))),
Etienne Bergeronc87599f2016-05-12 04:32:47 +0000647 unless(hasLHS(AnyLiteralExpr)),
648 unless(hasDescendant(BannedIntegerLiteral)))
Etienne Bergeronbda187d2016-04-26 17:30:30 +0000649 .bind("binary"),
650 this);
Etienne Bergeronc87599f2016-05-12 04:32:47 +0000651
Gabor Horvathec87e172017-11-07 13:17:58 +0000652 // Conditional (trenary) operator with equivalent operands, like (Y ? X : X).
Gabor Horvath250c40d2017-11-27 15:05:24 +0000653 Finder->addMatcher(conditionalOperator(expressionsAreEquivalent(),
654 // Filter noisy false positives.
655 unless(conditionalOperatorIsInMacro()),
656 unless(isInTemplateInstantiation()))
657 .bind("cond"),
658 this);
Etienne Bergeronc87599f2016-05-12 04:32:47 +0000659
Gabor Horvathec87e172017-11-07 13:17:58 +0000660 // Overloaded operators with equivalent operands.
Etienne Bergeronc87599f2016-05-12 04:32:47 +0000661 Finder->addMatcher(
662 cxxOperatorCallExpr(
663 anyOf(
664 hasOverloadedOperatorName("-"), hasOverloadedOperatorName("/"),
665 hasOverloadedOperatorName("%"), hasOverloadedOperatorName("|"),
666 hasOverloadedOperatorName("&"), hasOverloadedOperatorName("^"),
667 hasOverloadedOperatorName("=="), hasOverloadedOperatorName("!="),
668 hasOverloadedOperatorName("<"), hasOverloadedOperatorName("<="),
669 hasOverloadedOperatorName(">"), hasOverloadedOperatorName(">="),
670 hasOverloadedOperatorName("&&"), hasOverloadedOperatorName("||"),
671 hasOverloadedOperatorName("=")),
672 parametersAreEquivalent(),
673 // Filter noisy false positives.
674 unless(isMacro()), unless(isInTemplateInstantiation()))
675 .bind("call"),
676 this);
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000677
678 // Match common expressions and apply more checks to find redundant
679 // sub-expressions.
680 // a) Expr <op> K1 == K2
681 // b) Expr <op> K1 == Expr
682 // c) Expr <op> K1 == Expr <op> K2
683 // see: 'checkArithmeticExpr' and 'checkBitwiseExpr'
684 const auto BinOpCstLeft = matchBinOpIntegerConstantExpr("lhs");
685 const auto BinOpCstRight = matchBinOpIntegerConstantExpr("rhs");
686 const auto CstRight = matchIntegerConstantExpr("rhs");
687 const auto SymRight = matchSymbolicExpr("rhs");
688
689 // Match expressions like: x <op> 0xFF == 0xF00.
690 Finder->addMatcher(binaryOperator(isComparisonOperator(),
691 hasEitherOperand(BinOpCstLeft),
692 hasEitherOperand(CstRight))
693 .bind("binop-const-compare-to-const"),
694 this);
695
696 // Match expressions like: x <op> 0xFF == x.
697 Finder->addMatcher(
698 binaryOperator(isComparisonOperator(),
699 anyOf(allOf(hasLHS(BinOpCstLeft), hasRHS(SymRight)),
700 allOf(hasLHS(SymRight), hasRHS(BinOpCstLeft))))
701 .bind("binop-const-compare-to-sym"),
702 this);
703
704 // Match expressions like: x <op> 10 == x <op> 12.
705 Finder->addMatcher(binaryOperator(isComparisonOperator(),
706 hasLHS(BinOpCstLeft), hasRHS(BinOpCstRight),
707 // Already reported as redundant.
708 unless(operandsAreEquivalent()))
709 .bind("binop-const-compare-to-binop-const"),
710 this);
711
712 // Match relational expressions combined with logical operators and find
713 // redundant sub-expressions.
714 // see: 'checkRelationalExpr'
715
716 // Match expressions like: x < 2 && x > 2.
717 const auto ComparisonLeft = matchRelationalIntegerConstantExpr("lhs");
718 const auto ComparisonRight = matchRelationalIntegerConstantExpr("rhs");
719 Finder->addMatcher(
720 binaryOperator(anyOf(hasOperatorName("||"), hasOperatorName("&&")),
721 hasLHS(ComparisonLeft), hasRHS(ComparisonRight),
722 // Already reported as redundant.
723 unless(operandsAreEquivalent()))
724 .bind("comparisons-of-symbol-and-const"),
725 this);
726}
727
728void RedundantExpressionCheck::checkArithmeticExpr(
729 const MatchFinder::MatchResult &Result) {
730 APSInt LhsValue, RhsValue;
731 const Expr *LhsSymbol = nullptr, *RhsSymbol = nullptr;
732 BinaryOperatorKind LhsOpcode, RhsOpcode;
733
734 if (const auto *ComparisonOperator = Result.Nodes.getNodeAs<BinaryOperator>(
735 "binop-const-compare-to-sym")) {
736 BinaryOperatorKind Opcode = ComparisonOperator->getOpcode();
737 if (!retrieveBinOpIntegerConstantExpr(Result, "lhs", LhsOpcode, LhsSymbol,
738 LhsValue) ||
739 !retrieveSymbolicExpr(Result, "rhs", RhsSymbol) ||
740 !areEquivalentExpr(LhsSymbol, RhsSymbol))
741 return;
742
743 // Check expressions: x + k == x or x - k == x.
744 if (LhsOpcode == BO_Add || LhsOpcode == BO_Sub) {
745 if ((LhsValue != 0 && Opcode == BO_EQ) ||
746 (LhsValue == 0 && Opcode == BO_NE))
747 diag(ComparisonOperator->getOperatorLoc(),
748 "logical expression is always false");
749 else if ((LhsValue == 0 && Opcode == BO_EQ) ||
750 (LhsValue != 0 && Opcode == BO_NE))
751 diag(ComparisonOperator->getOperatorLoc(),
752 "logical expression is always true");
753 }
754 } else if (const auto *ComparisonOperator =
755 Result.Nodes.getNodeAs<BinaryOperator>(
756 "binop-const-compare-to-binop-const")) {
757 BinaryOperatorKind Opcode = ComparisonOperator->getOpcode();
758
759 if (!retrieveBinOpIntegerConstantExpr(Result, "lhs", LhsOpcode, LhsSymbol,
760 LhsValue) ||
761 !retrieveBinOpIntegerConstantExpr(Result, "rhs", RhsOpcode, RhsSymbol,
762 RhsValue) ||
763 !areEquivalentExpr(LhsSymbol, RhsSymbol))
764 return;
765
Gabor Horvathec87e172017-11-07 13:17:58 +0000766 transformSubToCanonicalAddExpr(LhsOpcode, LhsValue);
767 transformSubToCanonicalAddExpr(RhsOpcode, RhsValue);
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000768
769 // Check expressions: x + 1 == x + 2 or x + 1 != x + 2.
770 if (LhsOpcode == BO_Add && RhsOpcode == BO_Add) {
771 if ((Opcode == BO_EQ && APSInt::compareValues(LhsValue, RhsValue) == 0) ||
772 (Opcode == BO_NE && APSInt::compareValues(LhsValue, RhsValue) != 0)) {
773 diag(ComparisonOperator->getOperatorLoc(),
774 "logical expression is always true");
775 } else if ((Opcode == BO_EQ &&
776 APSInt::compareValues(LhsValue, RhsValue) != 0) ||
777 (Opcode == BO_NE &&
778 APSInt::compareValues(LhsValue, RhsValue) == 0)) {
779 diag(ComparisonOperator->getOperatorLoc(),
780 "logical expression is always false");
781 }
782 }
783 }
784}
785
786void RedundantExpressionCheck::checkBitwiseExpr(
787 const MatchFinder::MatchResult &Result) {
788 if (const auto *ComparisonOperator = Result.Nodes.getNodeAs<BinaryOperator>(
789 "binop-const-compare-to-const")) {
790 BinaryOperatorKind Opcode = ComparisonOperator->getOpcode();
791
792 APSInt LhsValue, RhsValue;
793 const Expr *LhsSymbol = nullptr;
794 BinaryOperatorKind LhsOpcode;
795 if (!retrieveBinOpIntegerConstantExpr(Result, "lhs", LhsOpcode, LhsSymbol,
796 LhsValue) ||
797 !retrieveIntegerConstantExpr(Result, "rhs", RhsValue))
798 return;
799
800 uint64_t LhsConstant = LhsValue.getZExtValue();
801 uint64_t RhsConstant = RhsValue.getZExtValue();
802 SourceLocation Loc = ComparisonOperator->getOperatorLoc();
803
804 // Check expression: x & k1 == k2 (i.e. x & 0xFF == 0xF00)
805 if (LhsOpcode == BO_And && (LhsConstant & RhsConstant) != RhsConstant) {
806 if (Opcode == BO_EQ)
807 diag(Loc, "logical expression is always false");
808 else if (Opcode == BO_NE)
809 diag(Loc, "logical expression is always true");
810 }
811
812 // Check expression: x | k1 == k2 (i.e. x | 0xFF == 0xF00)
813 if (LhsOpcode == BO_Or && (LhsConstant | RhsConstant) != RhsConstant) {
814 if (Opcode == BO_EQ)
815 diag(Loc, "logical expression is always false");
816 else if (Opcode == BO_NE)
817 diag(Loc, "logical expression is always true");
818 }
819 }
820}
821
822void RedundantExpressionCheck::checkRelationalExpr(
823 const MatchFinder::MatchResult &Result) {
824 if (const auto *ComparisonOperator = Result.Nodes.getNodeAs<BinaryOperator>(
825 "comparisons-of-symbol-and-const")) {
826 // Matched expressions are: (x <op> k1) <REL> (x <op> k2).
Gabor Horvathec87e172017-11-07 13:17:58 +0000827 // E.g.: (X < 2) && (X > 4)
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000828 BinaryOperatorKind Opcode = ComparisonOperator->getOpcode();
829
830 const Expr *LhsExpr = nullptr, *RhsExpr = nullptr;
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000831 const Expr *LhsSymbol = nullptr, *RhsSymbol = nullptr;
Gabor Horvathec87e172017-11-07 13:17:58 +0000832 const Expr *LhsConst = nullptr, *RhsConst = nullptr;
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000833 BinaryOperatorKind LhsOpcode, RhsOpcode;
Gabor Horvathec87e172017-11-07 13:17:58 +0000834 APSInt LhsValue, RhsValue;
835
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000836 if (!retrieveRelationalIntegerConstantExpr(
Gabor Horvathec87e172017-11-07 13:17:58 +0000837 Result, "lhs", LhsExpr, LhsOpcode, LhsSymbol, LhsValue, LhsConst) ||
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000838 !retrieveRelationalIntegerConstantExpr(
Gabor Horvathec87e172017-11-07 13:17:58 +0000839 Result, "rhs", RhsExpr, RhsOpcode, RhsSymbol, RhsValue, RhsConst) ||
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000840 !areEquivalentExpr(LhsSymbol, RhsSymbol))
841 return;
842
Gabor Horvathec87e172017-11-07 13:17:58 +0000843 // Bring expr to a canonical form: smallest constant must be on the left.
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000844 if (APSInt::compareValues(LhsValue, RhsValue) > 0) {
845 std::swap(LhsExpr, RhsExpr);
846 std::swap(LhsValue, RhsValue);
847 std::swap(LhsSymbol, RhsSymbol);
848 std::swap(LhsOpcode, RhsOpcode);
849 }
850
Gabor Horvathec87e172017-11-07 13:17:58 +0000851 // Constants come from two different macros, or one of them is a macro.
852 if (areExprsFromDifferentMacros(LhsConst, RhsConst, Result.Context) ||
853 areExprsMacroAndNonMacro(LhsConst, RhsConst))
854 return;
855
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000856 if ((Opcode == BO_LAnd || Opcode == BO_LOr) &&
857 areEquivalentRanges(LhsOpcode, LhsValue, RhsOpcode, RhsValue)) {
858 diag(ComparisonOperator->getOperatorLoc(),
Gabor Horvathec87e172017-11-07 13:17:58 +0000859 "equivalent expression on both sides of logical operator");
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000860 return;
861 }
862
863 if (Opcode == BO_LAnd) {
864 if (areExclusiveRanges(LhsOpcode, LhsValue, RhsOpcode, RhsValue)) {
865 diag(ComparisonOperator->getOperatorLoc(),
866 "logical expression is always false");
867 } else if (rangeSubsumesRange(LhsOpcode, LhsValue, RhsOpcode, RhsValue)) {
868 diag(LhsExpr->getExprLoc(), "expression is redundant");
869 } else if (rangeSubsumesRange(RhsOpcode, RhsValue, LhsOpcode, LhsValue)) {
870 diag(RhsExpr->getExprLoc(), "expression is redundant");
871 }
872 }
873
874 if (Opcode == BO_LOr) {
875 if (rangesFullyCoverDomain(LhsOpcode, LhsValue, RhsOpcode, RhsValue)) {
876 diag(ComparisonOperator->getOperatorLoc(),
877 "logical expression is always true");
878 } else if (rangeSubsumesRange(LhsOpcode, LhsValue, RhsOpcode, RhsValue)) {
879 diag(RhsExpr->getExprLoc(), "expression is redundant");
880 } else if (rangeSubsumesRange(RhsOpcode, RhsValue, LhsOpcode, LhsValue)) {
881 diag(LhsExpr->getExprLoc(), "expression is redundant");
882 }
883 }
884 }
Etienne Bergeronbda187d2016-04-26 17:30:30 +0000885}
886
887void RedundantExpressionCheck::check(const MatchFinder::MatchResult &Result) {
Gabor Horvathec87e172017-11-07 13:17:58 +0000888 if (const auto *BinOp = Result.Nodes.getNodeAs<BinaryOperator>("binary")) {
Gabor Horvathec87e172017-11-07 13:17:58 +0000889 // If the expression's constants are macros, check whether they are
890 // intentional.
891 if (areSidesBinaryConstExpressions(BinOp, Result.Context)) {
892 const Expr *LhsConst = nullptr, *RhsConst = nullptr;
893 BinaryOperatorKind MainOpcode, SideOpcode;
894
Gabor Horvath250c40d2017-11-27 15:05:24 +0000895 if (!retrieveConstExprFromBothSides(BinOp, MainOpcode, SideOpcode,
896 LhsConst, RhsConst, Result.Context))
897 return;
Gabor Horvathec87e172017-11-07 13:17:58 +0000898
899 if (areExprsFromDifferentMacros(LhsConst, RhsConst, Result.Context) ||
900 areExprsMacroAndNonMacro(LhsConst, RhsConst))
901 return;
902 }
903
904 diag(BinOp->getOperatorLoc(), "both sides of operator are equivalent");
905 }
906
907 if (const auto *CondOp =
908 Result.Nodes.getNodeAs<ConditionalOperator>("cond")) {
909 const Expr *TrueExpr = CondOp->getTrueExpr();
910 const Expr *FalseExpr = CondOp->getFalseExpr();
911
912 if (areExprsFromDifferentMacros(TrueExpr, FalseExpr, Result.Context) ||
913 areExprsMacroAndNonMacro(TrueExpr, FalseExpr))
914 return;
915 diag(CondOp->getColonLoc(),
916 "'true' and 'false' expressions are equivalent");
917 }
918
919 if (const auto *Call = Result.Nodes.getNodeAs<CXXOperatorCallExpr>("call")) {
Gabor Horvath250c40d2017-11-27 15:05:24 +0000920 const auto *OverloadedFunctionDecl = dyn_cast_or_null<FunctionDecl>(Call->getCalleeDecl());
921 if (!OverloadedFunctionDecl)
922 return;
923
924 if (canOverloadedOperatorArgsBeModified(OverloadedFunctionDecl, true))
925 return;
926
Gabor Horvathec87e172017-11-07 13:17:58 +0000927 diag(Call->getOperatorLoc(),
928 "both sides of overloaded operator are equivalent");
929 }
930
931 // Check for the following bound expressions:
932 // - "binop-const-compare-to-sym",
933 // - "binop-const-compare-to-binop-const",
934 // Produced message:
935 // -> "logical expression is always false/true"
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000936 checkArithmeticExpr(Result);
Gabor Horvathec87e172017-11-07 13:17:58 +0000937
938 // Check for the following bound expression:
939 // - "binop-const-compare-to-const",
940 // Produced message:
941 // -> "logical expression is always false/true"
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000942 checkBitwiseExpr(Result);
Gabor Horvathec87e172017-11-07 13:17:58 +0000943
944 // Check for te following bound expression:
945 // - "comparisons-of-symbol-and-const",
946 // Produced messages:
947 // -> "equivalent expression on both sides of logical operator",
948 // -> "logical expression is always false/true"
949 // -> "expression is redundant"
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000950 checkRelationalExpr(Result);
Etienne Bergeronbda187d2016-04-26 17:30:30 +0000951}
952
953} // namespace misc
954} // namespace tidy
955} // namespace clang