blob: e9b0f4d0c58efebd4d00db522b474fbaeb4c08e9 [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 {
Etienne Bergeron00639bc2016-07-07 04:03:05 +000035namespace {
36using llvm::APSInt;
Etienne Bergeron00639bc2016-07-07 04:03:05 +000037
Benjamin Kramer492f1cc2018-02-02 13:23:24 +000038static constexpr llvm::StringLiteral KnownBannedMacroNames[] = {
39 "EAGAIN",
40 "EWOULDBLOCK",
41 "SIGCLD",
42 "SIGCHLD",
43};
Etienne Bergeronc87599f2016-05-12 04:32:47 +000044
Etienne Bergeron00639bc2016-07-07 04:03:05 +000045static bool incrementWithoutOverflow(const APSInt &Value, APSInt &Result) {
46 Result = Value;
47 ++Result;
48 return Value < Result;
49}
50
Etienne Bergeronc87599f2016-05-12 04:32:47 +000051static bool areEquivalentNameSpecifier(const NestedNameSpecifier *Left,
52 const NestedNameSpecifier *Right) {
53 llvm::FoldingSetNodeID LeftID, RightID;
54 Left->Profile(LeftID);
55 Right->Profile(RightID);
56 return LeftID == RightID;
57}
58
59static bool areEquivalentExpr(const Expr *Left, const Expr *Right) {
Etienne Bergeronbda187d2016-04-26 17:30:30 +000060 if (!Left || !Right)
61 return !Left && !Right;
62
63 Left = Left->IgnoreParens();
64 Right = Right->IgnoreParens();
65
66 // Compare classes.
67 if (Left->getStmtClass() != Right->getStmtClass())
68 return false;
69
70 // Compare children.
71 Expr::const_child_iterator LeftIter = Left->child_begin();
72 Expr::const_child_iterator RightIter = Right->child_begin();
73 while (LeftIter != Left->child_end() && RightIter != Right->child_end()) {
Etienne Bergeronc87599f2016-05-12 04:32:47 +000074 if (!areEquivalentExpr(dyn_cast<Expr>(*LeftIter),
75 dyn_cast<Expr>(*RightIter)))
Etienne Bergeronbda187d2016-04-26 17:30:30 +000076 return false;
77 ++LeftIter;
78 ++RightIter;
79 }
80 if (LeftIter != Left->child_end() || RightIter != Right->child_end())
81 return false;
82
83 // Perform extra checks.
84 switch (Left->getStmtClass()) {
85 default:
86 return false;
87
88 case Stmt::CharacterLiteralClass:
89 return cast<CharacterLiteral>(Left)->getValue() ==
90 cast<CharacterLiteral>(Right)->getValue();
91 case Stmt::IntegerLiteralClass: {
92 llvm::APInt LeftLit = cast<IntegerLiteral>(Left)->getValue();
93 llvm::APInt RightLit = cast<IntegerLiteral>(Right)->getValue();
Etienne Bergeronc87599f2016-05-12 04:32:47 +000094 return LeftLit.getBitWidth() == RightLit.getBitWidth() &&
95 LeftLit == RightLit;
Etienne Bergeronbda187d2016-04-26 17:30:30 +000096 }
97 case Stmt::FloatingLiteralClass:
98 return cast<FloatingLiteral>(Left)->getValue().bitwiseIsEqual(
99 cast<FloatingLiteral>(Right)->getValue());
100 case Stmt::StringLiteralClass:
101 return cast<StringLiteral>(Left)->getBytes() ==
102 cast<StringLiteral>(Right)->getBytes();
Gabor Horvath250c40d2017-11-27 15:05:24 +0000103 case Stmt::CXXOperatorCallExprClass:
104 return cast<CXXOperatorCallExpr>(Left)->getOperator() ==
105 cast<CXXOperatorCallExpr>(Right)->getOperator();
Etienne Bergeronc87599f2016-05-12 04:32:47 +0000106 case Stmt::DependentScopeDeclRefExprClass:
107 if (cast<DependentScopeDeclRefExpr>(Left)->getDeclName() !=
108 cast<DependentScopeDeclRefExpr>(Right)->getDeclName())
109 return false;
110 return areEquivalentNameSpecifier(
111 cast<DependentScopeDeclRefExpr>(Left)->getQualifier(),
112 cast<DependentScopeDeclRefExpr>(Right)->getQualifier());
Etienne Bergeronbda187d2016-04-26 17:30:30 +0000113 case Stmt::DeclRefExprClass:
114 return cast<DeclRefExpr>(Left)->getDecl() ==
115 cast<DeclRefExpr>(Right)->getDecl();
116 case Stmt::MemberExprClass:
117 return cast<MemberExpr>(Left)->getMemberDecl() ==
118 cast<MemberExpr>(Right)->getMemberDecl();
Gabor Horvathec87e172017-11-07 13:17:58 +0000119 case Stmt::CXXFunctionalCastExprClass:
Etienne Bergeronbda187d2016-04-26 17:30:30 +0000120 case Stmt::CStyleCastExprClass:
Gabor Horvathec87e172017-11-07 13:17:58 +0000121 return cast<ExplicitCastExpr>(Left)->getTypeAsWritten() ==
122 cast<ExplicitCastExpr>(Right)->getTypeAsWritten();
Etienne Bergeronbda187d2016-04-26 17:30:30 +0000123 case Stmt::CallExprClass:
124 case Stmt::ImplicitCastExprClass:
125 case Stmt::ArraySubscriptExprClass:
126 return true;
Etienne Bergeronbda187d2016-04-26 17:30:30 +0000127 case Stmt::UnaryOperatorClass:
128 if (cast<UnaryOperator>(Left)->isIncrementDecrementOp())
129 return false;
130 return cast<UnaryOperator>(Left)->getOpcode() ==
131 cast<UnaryOperator>(Right)->getOpcode();
132 case Stmt::BinaryOperatorClass:
133 return cast<BinaryOperator>(Left)->getOpcode() ==
134 cast<BinaryOperator>(Right)->getOpcode();
135 }
136}
137
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000138// For a given expression 'x', returns whether the ranges covered by the
139// relational operators are equivalent (i.e. x <= 4 is equivalent to x < 5).
140static bool areEquivalentRanges(BinaryOperatorKind OpcodeLHS,
141 const APSInt &ValueLHS,
142 BinaryOperatorKind OpcodeRHS,
143 const APSInt &ValueRHS) {
144 assert(APSInt::compareValues(ValueLHS, ValueRHS) <= 0 &&
145 "Values must be ordered");
146 // Handle the case where constants are the same: x <= 4 <==> x <= 4.
147 if (APSInt::compareValues(ValueLHS, ValueRHS) == 0)
148 return OpcodeLHS == OpcodeRHS;
149
150 // Handle the case where constants are off by one: x <= 4 <==> x < 5.
151 APSInt ValueLHS_plus1;
152 return ((OpcodeLHS == BO_LE && OpcodeRHS == BO_LT) ||
153 (OpcodeLHS == BO_GT && OpcodeRHS == BO_GE)) &&
154 incrementWithoutOverflow(ValueLHS, ValueLHS_plus1) &&
155 APSInt::compareValues(ValueLHS_plus1, ValueRHS) == 0;
156}
157
158// For a given expression 'x', returns whether the ranges covered by the
159// relational operators are fully disjoint (i.e. x < 4 and x > 7).
160static bool areExclusiveRanges(BinaryOperatorKind OpcodeLHS,
161 const APSInt &ValueLHS,
162 BinaryOperatorKind OpcodeRHS,
163 const APSInt &ValueRHS) {
164 assert(APSInt::compareValues(ValueLHS, ValueRHS) <= 0 &&
165 "Values must be ordered");
166
167 // Handle cases where the constants are the same.
168 if (APSInt::compareValues(ValueLHS, ValueRHS) == 0) {
169 switch (OpcodeLHS) {
170 case BO_EQ:
171 return OpcodeRHS == BO_NE || OpcodeRHS == BO_GT || OpcodeRHS == BO_LT;
172 case BO_NE:
173 return OpcodeRHS == BO_EQ;
174 case BO_LE:
175 return OpcodeRHS == BO_GT;
176 case BO_GE:
177 return OpcodeRHS == BO_LT;
178 case BO_LT:
179 return OpcodeRHS == BO_EQ || OpcodeRHS == BO_GT || OpcodeRHS == BO_GE;
180 case BO_GT:
181 return OpcodeRHS == BO_EQ || OpcodeRHS == BO_LT || OpcodeRHS == BO_LE;
182 default:
183 return false;
184 }
185 }
186
187 // Handle cases where the constants are different.
Eugene Zelenko90c117a2016-11-01 18:33:50 +0000188 if ((OpcodeLHS == BO_EQ || OpcodeLHS == BO_LT || OpcodeLHS == BO_LE) &&
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000189 (OpcodeRHS == BO_EQ || OpcodeRHS == BO_GT || OpcodeRHS == BO_GE))
190 return true;
191
192 // Handle the case where constants are off by one: x > 5 && x < 6.
193 APSInt ValueLHS_plus1;
194 if (OpcodeLHS == BO_GT && OpcodeRHS == BO_LT &&
195 incrementWithoutOverflow(ValueLHS, ValueLHS_plus1) &&
196 APSInt::compareValues(ValueLHS_plus1, ValueRHS) == 0)
197 return true;
198
199 return false;
200}
201
202// Returns whether the ranges covered by the union of both relational
Gabor Horvath91c66712017-12-20 12:22:16 +0000203// expressions cover the whole domain (i.e. x < 10 and x > 0).
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000204static bool rangesFullyCoverDomain(BinaryOperatorKind OpcodeLHS,
205 const APSInt &ValueLHS,
206 BinaryOperatorKind OpcodeRHS,
207 const APSInt &ValueRHS) {
208 assert(APSInt::compareValues(ValueLHS, ValueRHS) <= 0 &&
209 "Values must be ordered");
210
211 // Handle cases where the constants are the same: x < 5 || x >= 5.
212 if (APSInt::compareValues(ValueLHS, ValueRHS) == 0) {
213 switch (OpcodeLHS) {
214 case BO_EQ:
215 return OpcodeRHS == BO_NE;
216 case BO_NE:
217 return OpcodeRHS == BO_EQ;
218 case BO_LE:
219 return OpcodeRHS == BO_GT || OpcodeRHS == BO_GE;
220 case BO_LT:
221 return OpcodeRHS == BO_GE;
222 case BO_GE:
223 return OpcodeRHS == BO_LT || OpcodeRHS == BO_LE;
224 case BO_GT:
225 return OpcodeRHS == BO_LE;
226 default:
227 return false;
228 }
229 }
230
231 // Handle the case where constants are off by one: x <= 4 || x >= 5.
232 APSInt ValueLHS_plus1;
233 if (OpcodeLHS == BO_LE && OpcodeRHS == BO_GE &&
234 incrementWithoutOverflow(ValueLHS, ValueLHS_plus1) &&
235 APSInt::compareValues(ValueLHS_plus1, ValueRHS) == 0)
236 return true;
237
238 // Handle cases where the constants are different: x > 4 || x <= 7.
239 if ((OpcodeLHS == BO_GT || OpcodeLHS == BO_GE) &&
240 (OpcodeRHS == BO_LT || OpcodeRHS == BO_LE))
241 return true;
242
Alexander Kornienkoc3acd2e2017-03-23 15:13:54 +0000243 // Handle cases where constants are different but both ops are !=, like:
244 // x != 5 || x != 10
245 if (OpcodeLHS == BO_NE && OpcodeRHS == BO_NE)
246 return true;
247
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000248 return false;
249}
250
251static bool rangeSubsumesRange(BinaryOperatorKind OpcodeLHS,
252 const APSInt &ValueLHS,
253 BinaryOperatorKind OpcodeRHS,
254 const APSInt &ValueRHS) {
255 int Comparison = APSInt::compareValues(ValueLHS, ValueRHS);
256 switch (OpcodeLHS) {
257 case BO_EQ:
258 return OpcodeRHS == BO_EQ && Comparison == 0;
259 case BO_NE:
260 return (OpcodeRHS == BO_NE && Comparison == 0) ||
261 (OpcodeRHS == BO_EQ && Comparison != 0) ||
262 (OpcodeRHS == BO_LT && Comparison >= 0) ||
263 (OpcodeRHS == BO_LE && Comparison > 0) ||
264 (OpcodeRHS == BO_GT && Comparison <= 0) ||
265 (OpcodeRHS == BO_GE && Comparison < 0);
266
267 case BO_LT:
268 return ((OpcodeRHS == BO_LT && Comparison >= 0) ||
269 (OpcodeRHS == BO_LE && Comparison > 0) ||
270 (OpcodeRHS == BO_EQ && Comparison > 0));
271 case BO_GT:
272 return ((OpcodeRHS == BO_GT && Comparison <= 0) ||
273 (OpcodeRHS == BO_GE && Comparison < 0) ||
274 (OpcodeRHS == BO_EQ && Comparison < 0));
275 case BO_LE:
276 return (OpcodeRHS == BO_LT || OpcodeRHS == BO_LE || OpcodeRHS == BO_EQ) &&
277 Comparison >= 0;
278 case BO_GE:
279 return (OpcodeRHS == BO_GT || OpcodeRHS == BO_GE || OpcodeRHS == BO_EQ) &&
280 Comparison <= 0;
281 default:
282 return false;
283 }
284}
285
Gabor Horvathec87e172017-11-07 13:17:58 +0000286static void transformSubToCanonicalAddExpr(BinaryOperatorKind &Opcode,
287 APSInt &Value) {
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000288 if (Opcode == BO_Sub) {
289 Opcode = BO_Add;
290 Value = -Value;
291 }
292}
293
294AST_MATCHER(Expr, isIntegerConstantExpr) {
295 if (Node.isInstantiationDependent())
296 return false;
297 return Node.isIntegerConstantExpr(Finder->getASTContext());
298}
299
Gabor Horvathec87e172017-11-07 13:17:58 +0000300AST_MATCHER(BinaryOperator, operandsAreEquivalent) {
301 return areEquivalentExpr(Node.getLHS(), Node.getRHS());
302}
303
304AST_MATCHER(ConditionalOperator, expressionsAreEquivalent) {
305 return areEquivalentExpr(Node.getTrueExpr(), Node.getFalseExpr());
306}
307
308AST_MATCHER(CallExpr, parametersAreEquivalent) {
309 return Node.getNumArgs() == 2 &&
310 areEquivalentExpr(Node.getArg(0), Node.getArg(1));
311}
312
313AST_MATCHER(BinaryOperator, binaryOperatorIsInMacro) {
314 return Node.getOperatorLoc().isMacroID();
315}
316
317AST_MATCHER(ConditionalOperator, conditionalOperatorIsInMacro) {
318 return Node.getQuestionLoc().isMacroID() || Node.getColonLoc().isMacroID();
319}
320
321AST_MATCHER(Expr, isMacro) { return Node.getExprLoc().isMacroID(); }
322
Benjamin Kramer492f1cc2018-02-02 13:23:24 +0000323AST_MATCHER_P(Expr, expandedByMacro, ArrayRef<llvm::StringLiteral>, Names) {
Gabor Horvathec87e172017-11-07 13:17:58 +0000324 const SourceManager &SM = Finder->getASTContext().getSourceManager();
325 const LangOptions &LO = Finder->getASTContext().getLangOpts();
326 SourceLocation Loc = Node.getExprLoc();
327 while (Loc.isMacroID()) {
328 StringRef MacroName = Lexer::getImmediateMacroName(Loc, SM, LO);
Benjamin Kramer492f1cc2018-02-02 13:23:24 +0000329 if (llvm::is_contained(Names, MacroName))
Gabor Horvathec87e172017-11-07 13:17:58 +0000330 return true;
331 Loc = SM.getImmediateMacroCallerLoc(Loc);
332 }
333 return false;
334}
335
336// Returns a matcher for integer constant expressions.
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000337static ast_matchers::internal::Matcher<Expr>
338matchIntegerConstantExpr(StringRef Id) {
339 std::string CstId = (Id + "-const").str();
340 return expr(isIntegerConstantExpr()).bind(CstId);
341}
342
Gabor Horvathec87e172017-11-07 13:17:58 +0000343// Retrieves the integer expression matched by 'matchIntegerConstantExpr' with
344// name 'Id' and stores it into 'ConstExpr', the value of the expression is
345// stored into `Value`.
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000346static bool retrieveIntegerConstantExpr(const MatchFinder::MatchResult &Result,
Gabor Horvathec87e172017-11-07 13:17:58 +0000347 StringRef Id, APSInt &Value,
348 const Expr *&ConstExpr) {
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000349 std::string CstId = (Id + "-const").str();
Gabor Horvathec87e172017-11-07 13:17:58 +0000350 ConstExpr = Result.Nodes.getNodeAs<Expr>(CstId);
351 return ConstExpr && ConstExpr->isIntegerConstantExpr(Value, *Result.Context);
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000352}
353
Gabor Horvathec87e172017-11-07 13:17:58 +0000354// Overloaded `retrieveIntegerConstantExpr` for compatibility.
355static bool retrieveIntegerConstantExpr(const MatchFinder::MatchResult &Result,
356 StringRef Id, APSInt &Value) {
357 const Expr *ConstExpr = nullptr;
358 return retrieveIntegerConstantExpr(Result, Id, Value, ConstExpr);
359}
360
361// Returns a matcher for symbolic expressions (matches every expression except
362// ingeter constant expressions).
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000363static ast_matchers::internal::Matcher<Expr> matchSymbolicExpr(StringRef Id) {
364 std::string SymId = (Id + "-sym").str();
365 return ignoringParenImpCasts(
366 expr(unless(isIntegerConstantExpr())).bind(SymId));
367}
368
Gabor Horvathec87e172017-11-07 13:17:58 +0000369// Retrieves the expression matched by 'matchSymbolicExpr' with name 'Id' and
370// stores it into 'SymExpr'.
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000371static bool retrieveSymbolicExpr(const MatchFinder::MatchResult &Result,
372 StringRef Id, const Expr *&SymExpr) {
373 std::string SymId = (Id + "-sym").str();
374 if (const auto *Node = Result.Nodes.getNodeAs<Expr>(SymId)) {
375 SymExpr = Node;
376 return true;
377 }
378 return false;
379}
380
381// Match a binary operator between a symbolic expression and an integer constant
382// expression.
383static ast_matchers::internal::Matcher<Expr>
384matchBinOpIntegerConstantExpr(StringRef Id) {
385 const auto BinOpCstExpr =
386 expr(
387 anyOf(binaryOperator(anyOf(hasOperatorName("+"), hasOperatorName("|"),
388 hasOperatorName("&")),
389 hasEitherOperand(matchSymbolicExpr(Id)),
390 hasEitherOperand(matchIntegerConstantExpr(Id))),
391 binaryOperator(hasOperatorName("-"),
392 hasLHS(matchSymbolicExpr(Id)),
393 hasRHS(matchIntegerConstantExpr(Id)))))
394 .bind(Id);
395 return ignoringParenImpCasts(BinOpCstExpr);
396}
397
Gabor Horvathec87e172017-11-07 13:17:58 +0000398// Retrieves sub-expressions matched by 'matchBinOpIntegerConstantExpr' with
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000399// name 'Id'.
400static bool
401retrieveBinOpIntegerConstantExpr(const MatchFinder::MatchResult &Result,
402 StringRef Id, BinaryOperatorKind &Opcode,
403 const Expr *&Symbol, APSInt &Value) {
404 if (const auto *BinExpr = Result.Nodes.getNodeAs<BinaryOperator>(Id)) {
405 Opcode = BinExpr->getOpcode();
406 return retrieveSymbolicExpr(Result, Id, Symbol) &&
407 retrieveIntegerConstantExpr(Result, Id, Value);
408 }
409 return false;
410}
411
Gabor Horvathec87e172017-11-07 13:17:58 +0000412// Matches relational expressions: 'Expr <op> k' (i.e. x < 2, x != 3, 12 <= x).
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000413static ast_matchers::internal::Matcher<Expr>
414matchRelationalIntegerConstantExpr(StringRef Id) {
415 std::string CastId = (Id + "-cast").str();
416 std::string SwapId = (Id + "-swap").str();
417 std::string NegateId = (Id + "-negate").str();
Gabor Horvath250c40d2017-11-27 15:05:24 +0000418 std::string OverloadId = (Id + "-overload").str();
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000419
420 const auto RelationalExpr = ignoringParenImpCasts(binaryOperator(
421 isComparisonOperator(), expr().bind(Id),
422 anyOf(allOf(hasLHS(matchSymbolicExpr(Id)),
423 hasRHS(matchIntegerConstantExpr(Id))),
424 allOf(hasLHS(matchIntegerConstantExpr(Id)),
425 hasRHS(matchSymbolicExpr(Id)), expr().bind(SwapId)))));
426
427 // A cast can be matched as a comparator to zero. (i.e. if (x) is equivalent
428 // to if (x != 0)).
429 const auto CastExpr =
430 implicitCastExpr(hasCastKind(CK_IntegralToBoolean),
431 hasSourceExpression(matchSymbolicExpr(Id)))
432 .bind(CastId);
433
434 const auto NegateRelationalExpr =
435 unaryOperator(hasOperatorName("!"),
436 hasUnaryOperand(anyOf(CastExpr, RelationalExpr)))
437 .bind(NegateId);
438
Gabor Horvathec87e172017-11-07 13:17:58 +0000439 // Do not bind to double negation.
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000440 const auto NegateNegateRelationalExpr =
441 unaryOperator(hasOperatorName("!"),
442 hasUnaryOperand(unaryOperator(
443 hasOperatorName("!"),
444 hasUnaryOperand(anyOf(CastExpr, RelationalExpr)))));
445
Gabor Horvath250c40d2017-11-27 15:05:24 +0000446 const auto OverloadedOperatorExpr =
447 cxxOperatorCallExpr(
448 anyOf(hasOverloadedOperatorName("=="),
449 hasOverloadedOperatorName("!="), hasOverloadedOperatorName("<"),
450 hasOverloadedOperatorName("<="), hasOverloadedOperatorName(">"),
451 hasOverloadedOperatorName(">=")),
452 // Filter noisy false positives.
453 unless(isMacro()), unless(isInTemplateInstantiation()))
454 .bind(OverloadId);
455
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000456 return anyOf(RelationalExpr, CastExpr, NegateRelationalExpr,
Gabor Horvath250c40d2017-11-27 15:05:24 +0000457 NegateNegateRelationalExpr, OverloadedOperatorExpr);
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000458}
459
Gabor Horvath250c40d2017-11-27 15:05:24 +0000460// Checks whether a function param is non constant reference type, and may
461// be modified in the function.
462static bool isNonConstReferenceType(QualType ParamType) {
463 return ParamType->isReferenceType() &&
464 !ParamType.getNonReferenceType().isConstQualified();
465}
466
467// Checks whether the arguments of an overloaded operator can be modified in the
468// function.
469// For operators that take an instance and a constant as arguments, only the
470// first argument (the instance) needs to be checked, since the constant itself
471// is a temporary expression. Whether the second parameter is checked is
472// controlled by the parameter `ParamsToCheckCount`.
473static bool
474canOverloadedOperatorArgsBeModified(const FunctionDecl *OperatorDecl,
475 bool checkSecondParam) {
476 unsigned ParamCount = OperatorDecl->getNumParams();
477
478 // Overloaded operators declared inside a class have only one param.
479 // These functions must be declared const in order to not be able to modify
480 // the instance of the class they are called through.
481 if (ParamCount == 1 &&
482 !OperatorDecl->getType()->getAs<FunctionType>()->isConst())
483 return true;
484
485 if (isNonConstReferenceType(OperatorDecl->getParamDecl(0)->getType()))
486 return true;
487
488 return checkSecondParam && ParamCount == 2 &&
489 isNonConstReferenceType(OperatorDecl->getParamDecl(1)->getType());
490}
491
492// Retrieves sub-expressions matched by 'matchRelationalIntegerConstantExpr'
493// with name 'Id'.
Gabor Horvathec87e172017-11-07 13:17:58 +0000494static bool retrieveRelationalIntegerConstantExpr(
495 const MatchFinder::MatchResult &Result, StringRef Id,
496 const Expr *&OperandExpr, BinaryOperatorKind &Opcode, const Expr *&Symbol,
497 APSInt &Value, const Expr *&ConstExpr) {
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000498 std::string CastId = (Id + "-cast").str();
499 std::string SwapId = (Id + "-swap").str();
500 std::string NegateId = (Id + "-negate").str();
Gabor Horvath250c40d2017-11-27 15:05:24 +0000501 std::string OverloadId = (Id + "-overload").str();
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000502
503 if (const auto *Bin = Result.Nodes.getNodeAs<BinaryOperator>(Id)) {
504 // Operand received with explicit comparator.
505 Opcode = Bin->getOpcode();
506 OperandExpr = Bin;
Gabor Horvathec87e172017-11-07 13:17:58 +0000507
508 if (!retrieveIntegerConstantExpr(Result, Id, Value, ConstExpr))
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000509 return false;
510 } else if (const auto *Cast = Result.Nodes.getNodeAs<CastExpr>(CastId)) {
511 // Operand received with implicit comparator (cast).
512 Opcode = BO_NE;
513 OperandExpr = Cast;
Eugene Zelenko90c117a2016-11-01 18:33:50 +0000514 Value = APSInt(32, false);
Gabor Horvath250c40d2017-11-27 15:05:24 +0000515 } else if (const auto *OverloadedOperatorExpr =
516 Result.Nodes.getNodeAs<CXXOperatorCallExpr>(OverloadId)) {
517 const auto *OverloadedFunctionDecl = dyn_cast_or_null<FunctionDecl>(OverloadedOperatorExpr->getCalleeDecl());
518 if (!OverloadedFunctionDecl)
519 return false;
520
521 if (canOverloadedOperatorArgsBeModified(OverloadedFunctionDecl, false))
522 return false;
523
Gabor Horvath91c66712017-12-20 12:22:16 +0000524 if (canOverloadedOperatorArgsBeModified(OverloadedFunctionDecl, false))
525 return false;
526
Gabor Horvath250c40d2017-11-27 15:05:24 +0000527 if (!OverloadedOperatorExpr->getArg(1)->isIntegerConstantExpr(
528 Value, *Result.Context))
529 return false;
530
531 Symbol = OverloadedOperatorExpr->getArg(0);
532 OperandExpr = OverloadedOperatorExpr;
533 Opcode = BinaryOperator::getOverloadedOpcode(OverloadedOperatorExpr->getOperator());
534
535 return BinaryOperator::isComparisonOp(Opcode);
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000536 } else {
537 return false;
538 }
539
540 if (!retrieveSymbolicExpr(Result, Id, Symbol))
541 return false;
542
543 if (Result.Nodes.getNodeAs<Expr>(SwapId))
544 Opcode = BinaryOperator::reverseComparisonOp(Opcode);
545 if (Result.Nodes.getNodeAs<Expr>(NegateId))
546 Opcode = BinaryOperator::negateComparisonOp(Opcode);
Gabor Horvathec87e172017-11-07 13:17:58 +0000547 return true;
548}
549
550// Checks for expressions like (X == 4) && (Y != 9)
551static bool areSidesBinaryConstExpressions(const BinaryOperator *&BinOp, const ASTContext *AstCtx) {
552 const auto *LhsBinOp = dyn_cast<BinaryOperator>(BinOp->getLHS());
553 const auto *RhsBinOp = dyn_cast<BinaryOperator>(BinOp->getRHS());
554
555 if (!LhsBinOp || !RhsBinOp)
556 return false;
557
558 if ((LhsBinOp->getLHS()->isIntegerConstantExpr(*AstCtx) ||
559 LhsBinOp->getRHS()->isIntegerConstantExpr(*AstCtx)) &&
560 (RhsBinOp->getLHS()->isIntegerConstantExpr(*AstCtx) ||
561 RhsBinOp->getRHS()->isIntegerConstantExpr(*AstCtx)))
562 return true;
563 return false;
564}
565
566// Retrieves integer constant subexpressions from binary operator expressions
Gabor Horvath91c66712017-12-20 12:22:16 +0000567// that have two equivalent sides.
Gabor Horvathec87e172017-11-07 13:17:58 +0000568// E.g.: from (X == 5) && (X == 5) retrieves 5 and 5.
569static bool retrieveConstExprFromBothSides(const BinaryOperator *&BinOp,
570 BinaryOperatorKind &MainOpcode,
571 BinaryOperatorKind &SideOpcode,
572 const Expr *&LhsConst,
573 const Expr *&RhsConst,
574 const ASTContext *AstCtx) {
575 assert(areSidesBinaryConstExpressions(BinOp, AstCtx) &&
576 "Both sides of binary operator must be constant expressions!");
577
578 MainOpcode = BinOp->getOpcode();
579
580 const auto *BinOpLhs = cast<BinaryOperator>(BinOp->getLHS());
581 const auto *BinOpRhs = cast<BinaryOperator>(BinOp->getRHS());
582
583 LhsConst = BinOpLhs->getLHS()->isIntegerConstantExpr(*AstCtx)
584 ? BinOpLhs->getLHS()
585 : BinOpLhs->getRHS();
586 RhsConst = BinOpRhs->getLHS()->isIntegerConstantExpr(*AstCtx)
587 ? BinOpRhs->getLHS()
588 : BinOpRhs->getRHS();
589
590 if (!LhsConst || !RhsConst)
591 return false;
592
593 assert(BinOpLhs->getOpcode() == BinOpRhs->getOpcode() &&
594 "Sides of the binary operator must be equivalent expressions!");
595
596 SideOpcode = BinOpLhs->getOpcode();
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000597
598 return true;
599}
600
Gabor Horvathec87e172017-11-07 13:17:58 +0000601static bool areExprsFromDifferentMacros(const Expr *LhsExpr,
602 const Expr *RhsExpr,
603 const ASTContext *AstCtx) {
604 if (!LhsExpr || !RhsExpr)
605 return false;
606
607 SourceLocation LhsLoc = LhsExpr->getExprLoc();
608 SourceLocation RhsLoc = RhsExpr->getExprLoc();
609
610 if (!LhsLoc.isMacroID() || !RhsLoc.isMacroID())
611 return false;
612
613 const SourceManager &SM = AstCtx->getSourceManager();
614 const LangOptions &LO = AstCtx->getLangOpts();
615
616 return !(Lexer::getImmediateMacroName(LhsLoc, SM, LO) ==
617 Lexer::getImmediateMacroName(RhsLoc, SM, LO));
Etienne Bergeronbda187d2016-04-26 17:30:30 +0000618}
619
Gabor Horvath250c40d2017-11-27 15:05:24 +0000620static bool areExprsMacroAndNonMacro(const Expr *&LhsExpr,
621 const Expr *&RhsExpr) {
Gabor Horvathec87e172017-11-07 13:17:58 +0000622 if (!LhsExpr || !RhsExpr)
623 return false;
Etienne Bergeronc87599f2016-05-12 04:32:47 +0000624
Gabor Horvathec87e172017-11-07 13:17:58 +0000625 SourceLocation LhsLoc = LhsExpr->getExprLoc();
626 SourceLocation RhsLoc = RhsExpr->getExprLoc();
Etienne Bergeronc87599f2016-05-12 04:32:47 +0000627
Gabor Horvathec87e172017-11-07 13:17:58 +0000628 return LhsLoc.isMacroID() != RhsLoc.isMacroID();
Etienne Bergeronbda187d2016-04-26 17:30:30 +0000629}
Benjamin Kramera9bef622018-02-02 13:39:00 +0000630} // namespace
Etienne Bergeronbda187d2016-04-26 17:30:30 +0000631
632void RedundantExpressionCheck::registerMatchers(MatchFinder *Finder) {
633 const auto AnyLiteralExpr = ignoringParenImpCasts(
634 anyOf(cxxBoolLiteral(), characterLiteral(), integerLiteral()));
635
Gabor Horvath250c40d2017-11-27 15:05:24 +0000636 const auto BannedIntegerLiteral =
637 integerLiteral(expandedByMacro(KnownBannedMacroNames));
Etienne Bergeronc87599f2016-05-12 04:32:47 +0000638
Gabor Horvathec87e172017-11-07 13:17:58 +0000639 // Binary with equivalent operands, like (X != 2 && X != 2).
Etienne Bergeronbda187d2016-04-26 17:30:30 +0000640 Finder->addMatcher(
641 binaryOperator(anyOf(hasOperatorName("-"), hasOperatorName("/"),
642 hasOperatorName("%"), hasOperatorName("|"),
643 hasOperatorName("&"), hasOperatorName("^"),
644 matchers::isComparisonOperator(),
645 hasOperatorName("&&"), hasOperatorName("||"),
646 hasOperatorName("=")),
Etienne Bergeronc87599f2016-05-12 04:32:47 +0000647 operandsAreEquivalent(),
Etienne Bergeronbda187d2016-04-26 17:30:30 +0000648 // Filter noisy false positives.
Etienne Bergeronc87599f2016-05-12 04:32:47 +0000649 unless(isInTemplateInstantiation()),
650 unless(binaryOperatorIsInMacro()),
Etienne Bergeronbda187d2016-04-26 17:30:30 +0000651 unless(hasType(realFloatingPointType())),
652 unless(hasEitherOperand(hasType(realFloatingPointType()))),
Etienne Bergeronc87599f2016-05-12 04:32:47 +0000653 unless(hasLHS(AnyLiteralExpr)),
654 unless(hasDescendant(BannedIntegerLiteral)))
Etienne Bergeronbda187d2016-04-26 17:30:30 +0000655 .bind("binary"),
656 this);
Etienne Bergeronc87599f2016-05-12 04:32:47 +0000657
Gabor Horvathec87e172017-11-07 13:17:58 +0000658 // Conditional (trenary) operator with equivalent operands, like (Y ? X : X).
Gabor Horvath250c40d2017-11-27 15:05:24 +0000659 Finder->addMatcher(conditionalOperator(expressionsAreEquivalent(),
660 // Filter noisy false positives.
661 unless(conditionalOperatorIsInMacro()),
662 unless(isInTemplateInstantiation()))
663 .bind("cond"),
664 this);
Etienne Bergeronc87599f2016-05-12 04:32:47 +0000665
Gabor Horvathec87e172017-11-07 13:17:58 +0000666 // Overloaded operators with equivalent operands.
Etienne Bergeronc87599f2016-05-12 04:32:47 +0000667 Finder->addMatcher(
668 cxxOperatorCallExpr(
669 anyOf(
670 hasOverloadedOperatorName("-"), hasOverloadedOperatorName("/"),
671 hasOverloadedOperatorName("%"), hasOverloadedOperatorName("|"),
672 hasOverloadedOperatorName("&"), hasOverloadedOperatorName("^"),
673 hasOverloadedOperatorName("=="), hasOverloadedOperatorName("!="),
674 hasOverloadedOperatorName("<"), hasOverloadedOperatorName("<="),
675 hasOverloadedOperatorName(">"), hasOverloadedOperatorName(">="),
676 hasOverloadedOperatorName("&&"), hasOverloadedOperatorName("||"),
677 hasOverloadedOperatorName("=")),
678 parametersAreEquivalent(),
679 // Filter noisy false positives.
680 unless(isMacro()), unless(isInTemplateInstantiation()))
681 .bind("call"),
682 this);
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000683
Gabor Horvath91c66712017-12-20 12:22:16 +0000684 // Match expressions like: !(1 | 2 | 3)
685 Finder->addMatcher(
686 implicitCastExpr(
687 hasImplicitDestinationType(isInteger()),
688 has(unaryOperator(
689 hasOperatorName("!"),
690 hasUnaryOperand(ignoringParenImpCasts(binaryOperator(
691 anyOf(hasOperatorName("|"), hasOperatorName("&")),
692 hasLHS(anyOf(binaryOperator(anyOf(hasOperatorName("|"),
693 hasOperatorName("&"))),
694 integerLiteral())),
695 hasRHS(integerLiteral())))))
696 .bind("logical-bitwise-confusion"))),
697 this);
698
699 // Match expressions like: (X << 8) & 0xFF
700 Finder->addMatcher(
701 binaryOperator(hasOperatorName("&"),
702 hasEitherOperand(ignoringParenImpCasts(binaryOperator(
703 hasOperatorName("<<"),
704 hasRHS(ignoringParenImpCasts(
705 integerLiteral().bind("shift-const")))))),
706 hasEitherOperand(ignoringParenImpCasts(
707 integerLiteral().bind("and-const"))))
708 .bind("left-right-shift-confusion"),
709 this);
710
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000711 // Match common expressions and apply more checks to find redundant
712 // sub-expressions.
713 // a) Expr <op> K1 == K2
714 // b) Expr <op> K1 == Expr
715 // c) Expr <op> K1 == Expr <op> K2
716 // see: 'checkArithmeticExpr' and 'checkBitwiseExpr'
717 const auto BinOpCstLeft = matchBinOpIntegerConstantExpr("lhs");
718 const auto BinOpCstRight = matchBinOpIntegerConstantExpr("rhs");
719 const auto CstRight = matchIntegerConstantExpr("rhs");
720 const auto SymRight = matchSymbolicExpr("rhs");
721
722 // Match expressions like: x <op> 0xFF == 0xF00.
723 Finder->addMatcher(binaryOperator(isComparisonOperator(),
724 hasEitherOperand(BinOpCstLeft),
725 hasEitherOperand(CstRight))
726 .bind("binop-const-compare-to-const"),
727 this);
728
729 // Match expressions like: x <op> 0xFF == x.
730 Finder->addMatcher(
731 binaryOperator(isComparisonOperator(),
732 anyOf(allOf(hasLHS(BinOpCstLeft), hasRHS(SymRight)),
733 allOf(hasLHS(SymRight), hasRHS(BinOpCstLeft))))
734 .bind("binop-const-compare-to-sym"),
735 this);
736
737 // Match expressions like: x <op> 10 == x <op> 12.
738 Finder->addMatcher(binaryOperator(isComparisonOperator(),
739 hasLHS(BinOpCstLeft), hasRHS(BinOpCstRight),
740 // Already reported as redundant.
741 unless(operandsAreEquivalent()))
742 .bind("binop-const-compare-to-binop-const"),
743 this);
744
745 // Match relational expressions combined with logical operators and find
746 // redundant sub-expressions.
747 // see: 'checkRelationalExpr'
748
749 // Match expressions like: x < 2 && x > 2.
750 const auto ComparisonLeft = matchRelationalIntegerConstantExpr("lhs");
751 const auto ComparisonRight = matchRelationalIntegerConstantExpr("rhs");
752 Finder->addMatcher(
753 binaryOperator(anyOf(hasOperatorName("||"), hasOperatorName("&&")),
754 hasLHS(ComparisonLeft), hasRHS(ComparisonRight),
755 // Already reported as redundant.
756 unless(operandsAreEquivalent()))
757 .bind("comparisons-of-symbol-and-const"),
758 this);
759}
760
761void RedundantExpressionCheck::checkArithmeticExpr(
762 const MatchFinder::MatchResult &Result) {
763 APSInt LhsValue, RhsValue;
764 const Expr *LhsSymbol = nullptr, *RhsSymbol = nullptr;
765 BinaryOperatorKind LhsOpcode, RhsOpcode;
766
767 if (const auto *ComparisonOperator = Result.Nodes.getNodeAs<BinaryOperator>(
768 "binop-const-compare-to-sym")) {
769 BinaryOperatorKind Opcode = ComparisonOperator->getOpcode();
770 if (!retrieveBinOpIntegerConstantExpr(Result, "lhs", LhsOpcode, LhsSymbol,
771 LhsValue) ||
772 !retrieveSymbolicExpr(Result, "rhs", RhsSymbol) ||
773 !areEquivalentExpr(LhsSymbol, RhsSymbol))
774 return;
775
776 // Check expressions: x + k == x or x - k == x.
777 if (LhsOpcode == BO_Add || LhsOpcode == BO_Sub) {
778 if ((LhsValue != 0 && Opcode == BO_EQ) ||
779 (LhsValue == 0 && Opcode == BO_NE))
780 diag(ComparisonOperator->getOperatorLoc(),
781 "logical expression is always false");
782 else if ((LhsValue == 0 && Opcode == BO_EQ) ||
783 (LhsValue != 0 && Opcode == BO_NE))
784 diag(ComparisonOperator->getOperatorLoc(),
785 "logical expression is always true");
786 }
787 } else if (const auto *ComparisonOperator =
788 Result.Nodes.getNodeAs<BinaryOperator>(
789 "binop-const-compare-to-binop-const")) {
790 BinaryOperatorKind Opcode = ComparisonOperator->getOpcode();
791
792 if (!retrieveBinOpIntegerConstantExpr(Result, "lhs", LhsOpcode, LhsSymbol,
793 LhsValue) ||
794 !retrieveBinOpIntegerConstantExpr(Result, "rhs", RhsOpcode, RhsSymbol,
795 RhsValue) ||
796 !areEquivalentExpr(LhsSymbol, RhsSymbol))
797 return;
798
Gabor Horvathec87e172017-11-07 13:17:58 +0000799 transformSubToCanonicalAddExpr(LhsOpcode, LhsValue);
800 transformSubToCanonicalAddExpr(RhsOpcode, RhsValue);
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000801
802 // Check expressions: x + 1 == x + 2 or x + 1 != x + 2.
803 if (LhsOpcode == BO_Add && RhsOpcode == BO_Add) {
804 if ((Opcode == BO_EQ && APSInt::compareValues(LhsValue, RhsValue) == 0) ||
805 (Opcode == BO_NE && APSInt::compareValues(LhsValue, RhsValue) != 0)) {
806 diag(ComparisonOperator->getOperatorLoc(),
807 "logical expression is always true");
808 } else if ((Opcode == BO_EQ &&
809 APSInt::compareValues(LhsValue, RhsValue) != 0) ||
810 (Opcode == BO_NE &&
811 APSInt::compareValues(LhsValue, RhsValue) == 0)) {
812 diag(ComparisonOperator->getOperatorLoc(),
813 "logical expression is always false");
814 }
815 }
816 }
817}
818
Gabor Horvath91c66712017-12-20 12:22:16 +0000819static bool exprEvaluatesToZero(BinaryOperatorKind Opcode, APSInt Value) {
820 return (Opcode == BO_And || Opcode == BO_AndAssign) && Value == 0;
821}
822
823static bool exprEvaluatesToBitwiseNegatedZero(BinaryOperatorKind Opcode,
824 APSInt Value) {
825 return (Opcode == BO_Or || Opcode == BO_OrAssign) && ~Value == 0;
826}
827
828static bool exprEvaluatesToSymbolic(BinaryOperatorKind Opcode, APSInt Value) {
829 return ((Opcode == BO_Or || Opcode == BO_OrAssign) && Value == 0) ||
830 ((Opcode == BO_And || Opcode == BO_AndAssign) && ~Value == 0);
831}
832
833
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000834void RedundantExpressionCheck::checkBitwiseExpr(
835 const MatchFinder::MatchResult &Result) {
836 if (const auto *ComparisonOperator = Result.Nodes.getNodeAs<BinaryOperator>(
837 "binop-const-compare-to-const")) {
838 BinaryOperatorKind Opcode = ComparisonOperator->getOpcode();
839
840 APSInt LhsValue, RhsValue;
841 const Expr *LhsSymbol = nullptr;
842 BinaryOperatorKind LhsOpcode;
843 if (!retrieveBinOpIntegerConstantExpr(Result, "lhs", LhsOpcode, LhsSymbol,
844 LhsValue) ||
845 !retrieveIntegerConstantExpr(Result, "rhs", RhsValue))
846 return;
847
848 uint64_t LhsConstant = LhsValue.getZExtValue();
849 uint64_t RhsConstant = RhsValue.getZExtValue();
850 SourceLocation Loc = ComparisonOperator->getOperatorLoc();
851
852 // Check expression: x & k1 == k2 (i.e. x & 0xFF == 0xF00)
853 if (LhsOpcode == BO_And && (LhsConstant & RhsConstant) != RhsConstant) {
854 if (Opcode == BO_EQ)
855 diag(Loc, "logical expression is always false");
856 else if (Opcode == BO_NE)
857 diag(Loc, "logical expression is always true");
858 }
859
860 // Check expression: x | k1 == k2 (i.e. x | 0xFF == 0xF00)
861 if (LhsOpcode == BO_Or && (LhsConstant | RhsConstant) != RhsConstant) {
862 if (Opcode == BO_EQ)
863 diag(Loc, "logical expression is always false");
864 else if (Opcode == BO_NE)
865 diag(Loc, "logical expression is always true");
866 }
Gabor Horvath91c66712017-12-20 12:22:16 +0000867 } else if (const auto *IneffectiveOperator =
868 Result.Nodes.getNodeAs<BinaryOperator>(
869 "ineffective-bitwise")) {
870 APSInt Value;
871 const Expr *Sym = nullptr, *ConstExpr = nullptr;
872
873 if (!retrieveSymbolicExpr(Result, "ineffective-bitwise", Sym) ||
874 !retrieveIntegerConstantExpr(Result, "ineffective-bitwise", Value,
875 ConstExpr))
876 return;
877
878 if((Value != 0 && ~Value != 0) || Sym->getExprLoc().isMacroID())
879 return;
880
881 SourceLocation Loc = IneffectiveOperator->getOperatorLoc();
882
883 BinaryOperatorKind Opcode = IneffectiveOperator->getOpcode();
884 if (exprEvaluatesToZero(Opcode, Value)) {
885 diag(Loc, "expression always evaluates to 0");
886 } else if (exprEvaluatesToBitwiseNegatedZero(Opcode, Value)) {
Stephen Kelly43465bf2018-08-09 22:42:26 +0000887 SourceRange ConstExprRange(ConstExpr->getBeginLoc(),
Stephen Kellyc09197e2018-08-09 22:43:02 +0000888 ConstExpr->getEndLoc());
Gabor Horvath91c66712017-12-20 12:22:16 +0000889 StringRef ConstExprText = Lexer::getSourceText(
890 CharSourceRange::getTokenRange(ConstExprRange), *Result.SourceManager,
891 Result.Context->getLangOpts());
892
893 diag(Loc, "expression always evaluates to '%0'") << ConstExprText;
894
895 } else if (exprEvaluatesToSymbolic(Opcode, Value)) {
Stephen Kellyc09197e2018-08-09 22:43:02 +0000896 SourceRange SymExprRange(Sym->getBeginLoc(), Sym->getEndLoc());
Gabor Horvath91c66712017-12-20 12:22:16 +0000897
898 StringRef ExprText = Lexer::getSourceText(
899 CharSourceRange::getTokenRange(SymExprRange), *Result.SourceManager,
900 Result.Context->getLangOpts());
901
902 diag(Loc, "expression always evaluates to '%0'") << ExprText;
903 }
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000904 }
905}
906
907void RedundantExpressionCheck::checkRelationalExpr(
908 const MatchFinder::MatchResult &Result) {
909 if (const auto *ComparisonOperator = Result.Nodes.getNodeAs<BinaryOperator>(
910 "comparisons-of-symbol-and-const")) {
911 // Matched expressions are: (x <op> k1) <REL> (x <op> k2).
Gabor Horvathec87e172017-11-07 13:17:58 +0000912 // E.g.: (X < 2) && (X > 4)
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000913 BinaryOperatorKind Opcode = ComparisonOperator->getOpcode();
914
915 const Expr *LhsExpr = nullptr, *RhsExpr = nullptr;
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000916 const Expr *LhsSymbol = nullptr, *RhsSymbol = nullptr;
Gabor Horvathec87e172017-11-07 13:17:58 +0000917 const Expr *LhsConst = nullptr, *RhsConst = nullptr;
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000918 BinaryOperatorKind LhsOpcode, RhsOpcode;
Gabor Horvathec87e172017-11-07 13:17:58 +0000919 APSInt LhsValue, RhsValue;
920
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000921 if (!retrieveRelationalIntegerConstantExpr(
Gabor Horvathec87e172017-11-07 13:17:58 +0000922 Result, "lhs", LhsExpr, LhsOpcode, LhsSymbol, LhsValue, LhsConst) ||
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000923 !retrieveRelationalIntegerConstantExpr(
Gabor Horvathec87e172017-11-07 13:17:58 +0000924 Result, "rhs", RhsExpr, RhsOpcode, RhsSymbol, RhsValue, RhsConst) ||
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000925 !areEquivalentExpr(LhsSymbol, RhsSymbol))
926 return;
927
Gabor Horvathec87e172017-11-07 13:17:58 +0000928 // Bring expr to a canonical form: smallest constant must be on the left.
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000929 if (APSInt::compareValues(LhsValue, RhsValue) > 0) {
930 std::swap(LhsExpr, RhsExpr);
931 std::swap(LhsValue, RhsValue);
932 std::swap(LhsSymbol, RhsSymbol);
933 std::swap(LhsOpcode, RhsOpcode);
934 }
935
Gabor Horvathec87e172017-11-07 13:17:58 +0000936 // Constants come from two different macros, or one of them is a macro.
937 if (areExprsFromDifferentMacros(LhsConst, RhsConst, Result.Context) ||
938 areExprsMacroAndNonMacro(LhsConst, RhsConst))
939 return;
940
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000941 if ((Opcode == BO_LAnd || Opcode == BO_LOr) &&
942 areEquivalentRanges(LhsOpcode, LhsValue, RhsOpcode, RhsValue)) {
943 diag(ComparisonOperator->getOperatorLoc(),
Gabor Horvathec87e172017-11-07 13:17:58 +0000944 "equivalent expression on both sides of logical operator");
Etienne Bergeron00639bc2016-07-07 04:03:05 +0000945 return;
946 }
947
948 if (Opcode == BO_LAnd) {
949 if (areExclusiveRanges(LhsOpcode, LhsValue, RhsOpcode, RhsValue)) {
950 diag(ComparisonOperator->getOperatorLoc(),
951 "logical expression is always false");
952 } else if (rangeSubsumesRange(LhsOpcode, LhsValue, RhsOpcode, RhsValue)) {
953 diag(LhsExpr->getExprLoc(), "expression is redundant");
954 } else if (rangeSubsumesRange(RhsOpcode, RhsValue, LhsOpcode, LhsValue)) {
955 diag(RhsExpr->getExprLoc(), "expression is redundant");
956 }
957 }
958
959 if (Opcode == BO_LOr) {
960 if (rangesFullyCoverDomain(LhsOpcode, LhsValue, RhsOpcode, RhsValue)) {
961 diag(ComparisonOperator->getOperatorLoc(),
962 "logical expression is always true");
963 } else if (rangeSubsumesRange(LhsOpcode, LhsValue, RhsOpcode, RhsValue)) {
964 diag(RhsExpr->getExprLoc(), "expression is redundant");
965 } else if (rangeSubsumesRange(RhsOpcode, RhsValue, LhsOpcode, LhsValue)) {
966 diag(LhsExpr->getExprLoc(), "expression is redundant");
967 }
968 }
969 }
Etienne Bergeronbda187d2016-04-26 17:30:30 +0000970}
971
972void RedundantExpressionCheck::check(const MatchFinder::MatchResult &Result) {
Gabor Horvathec87e172017-11-07 13:17:58 +0000973 if (const auto *BinOp = Result.Nodes.getNodeAs<BinaryOperator>("binary")) {
Gabor Horvathec87e172017-11-07 13:17:58 +0000974 // If the expression's constants are macros, check whether they are
975 // intentional.
976 if (areSidesBinaryConstExpressions(BinOp, Result.Context)) {
977 const Expr *LhsConst = nullptr, *RhsConst = nullptr;
978 BinaryOperatorKind MainOpcode, SideOpcode;
979
Gabor Horvath250c40d2017-11-27 15:05:24 +0000980 if (!retrieveConstExprFromBothSides(BinOp, MainOpcode, SideOpcode,
981 LhsConst, RhsConst, Result.Context))
982 return;
Gabor Horvathec87e172017-11-07 13:17:58 +0000983
984 if (areExprsFromDifferentMacros(LhsConst, RhsConst, Result.Context) ||
985 areExprsMacroAndNonMacro(LhsConst, RhsConst))
986 return;
987 }
988
989 diag(BinOp->getOperatorLoc(), "both sides of operator are equivalent");
990 }
991
992 if (const auto *CondOp =
993 Result.Nodes.getNodeAs<ConditionalOperator>("cond")) {
994 const Expr *TrueExpr = CondOp->getTrueExpr();
995 const Expr *FalseExpr = CondOp->getFalseExpr();
996
997 if (areExprsFromDifferentMacros(TrueExpr, FalseExpr, Result.Context) ||
998 areExprsMacroAndNonMacro(TrueExpr, FalseExpr))
999 return;
1000 diag(CondOp->getColonLoc(),
1001 "'true' and 'false' expressions are equivalent");
1002 }
1003
1004 if (const auto *Call = Result.Nodes.getNodeAs<CXXOperatorCallExpr>("call")) {
Gabor Horvath250c40d2017-11-27 15:05:24 +00001005 const auto *OverloadedFunctionDecl = dyn_cast_or_null<FunctionDecl>(Call->getCalleeDecl());
1006 if (!OverloadedFunctionDecl)
1007 return;
1008
1009 if (canOverloadedOperatorArgsBeModified(OverloadedFunctionDecl, true))
1010 return;
1011
Gabor Horvathec87e172017-11-07 13:17:58 +00001012 diag(Call->getOperatorLoc(),
1013 "both sides of overloaded operator are equivalent");
1014 }
1015
Gabor Horvath91c66712017-12-20 12:22:16 +00001016 if (const auto *NegateOperator =
1017 Result.Nodes.getNodeAs<UnaryOperator>("logical-bitwise-confusion")) {
1018 SourceLocation OperatorLoc = NegateOperator->getOperatorLoc();
1019
1020 auto Diag =
1021 diag(OperatorLoc,
1022 "ineffective logical negation operator used; did you mean '~'?");
1023 SourceLocation LogicalNotLocation = OperatorLoc.getLocWithOffset(1);
1024
1025 if (!LogicalNotLocation.isMacroID())
1026 Diag << FixItHint::CreateReplacement(
1027 CharSourceRange::getCharRange(OperatorLoc, LogicalNotLocation), "~");
1028 }
1029
1030 if (const auto *BinaryAndExpr = Result.Nodes.getNodeAs<BinaryOperator>(
1031 "left-right-shift-confusion")) {
1032 const auto *ShiftingConst = Result.Nodes.getNodeAs<Expr>("shift-const");
1033 assert(ShiftingConst && "Expr* 'ShiftingConst' is nullptr!");
1034 APSInt ShiftingValue;
1035
1036 if (!ShiftingConst->isIntegerConstantExpr(ShiftingValue, *Result.Context))
1037 return;
1038
1039 const auto *AndConst = Result.Nodes.getNodeAs<Expr>("and-const");
1040 assert(AndConst && "Expr* 'AndCont' is nullptr!");
1041 APSInt AndValue;
1042 if (!AndConst->isIntegerConstantExpr(AndValue, *Result.Context))
1043 return;
1044
1045 // If ShiftingConst is shifted left with more bits than the position of the
1046 // leftmost 1 in the bit representation of AndValue, AndConstant is
1047 // ineffective.
Benjamin Kramer10db8d62018-02-02 13:23:21 +00001048 if (AndValue.getActiveBits() > ShiftingValue)
Gabor Horvath91c66712017-12-20 12:22:16 +00001049 return;
1050
1051 auto Diag = diag(BinaryAndExpr->getOperatorLoc(),
Alexander Kornienko396fc872018-02-01 16:39:12 +00001052 "ineffective bitwise and operation");
Gabor Horvath91c66712017-12-20 12:22:16 +00001053 }
1054
Gabor Horvathec87e172017-11-07 13:17:58 +00001055 // Check for the following bound expressions:
1056 // - "binop-const-compare-to-sym",
1057 // - "binop-const-compare-to-binop-const",
1058 // Produced message:
1059 // -> "logical expression is always false/true"
Etienne Bergeron00639bc2016-07-07 04:03:05 +00001060 checkArithmeticExpr(Result);
Gabor Horvathec87e172017-11-07 13:17:58 +00001061
1062 // Check for the following bound expression:
1063 // - "binop-const-compare-to-const",
Gabor Horvath91c66712017-12-20 12:22:16 +00001064 // - "ineffective-bitwise"
Gabor Horvathec87e172017-11-07 13:17:58 +00001065 // Produced message:
1066 // -> "logical expression is always false/true"
Gabor Horvath91c66712017-12-20 12:22:16 +00001067 // -> "expression always evaluates to ..."
Etienne Bergeron00639bc2016-07-07 04:03:05 +00001068 checkBitwiseExpr(Result);
Gabor Horvathec87e172017-11-07 13:17:58 +00001069
1070 // Check for te following bound expression:
1071 // - "comparisons-of-symbol-and-const",
1072 // Produced messages:
1073 // -> "equivalent expression on both sides of logical operator",
1074 // -> "logical expression is always false/true"
1075 // -> "expression is redundant"
Etienne Bergeron00639bc2016-07-07 04:03:05 +00001076 checkRelationalExpr(Result);
Etienne Bergeronbda187d2016-04-26 17:30:30 +00001077}
1078
1079} // namespace misc
1080} // namespace tidy
1081} // namespace clang