blob: fee7b03a74e8654b916bce9ffa48616d0d375aa4 [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"
12#include "clang/AST/ASTContext.h"
13#include "clang/ASTMatchers/ASTMatchFinder.h"
14
15using namespace clang::ast_matchers;
16
17namespace clang {
18namespace tidy {
19namespace misc {
20
21static bool AreIdenticalExpr(const Expr *Left, const Expr *Right) {
22 if (!Left || !Right)
23 return !Left && !Right;
24
25 Left = Left->IgnoreParens();
26 Right = Right->IgnoreParens();
27
28 // Compare classes.
29 if (Left->getStmtClass() != Right->getStmtClass())
30 return false;
31
32 // Compare children.
33 Expr::const_child_iterator LeftIter = Left->child_begin();
34 Expr::const_child_iterator RightIter = Right->child_begin();
35 while (LeftIter != Left->child_end() && RightIter != Right->child_end()) {
36 if (!AreIdenticalExpr(dyn_cast<Expr>(*LeftIter),
37 dyn_cast<Expr>(*RightIter)))
38 return false;
39 ++LeftIter;
40 ++RightIter;
41 }
42 if (LeftIter != Left->child_end() || RightIter != Right->child_end())
43 return false;
44
45 // Perform extra checks.
46 switch (Left->getStmtClass()) {
47 default:
48 return false;
49
50 case Stmt::CharacterLiteralClass:
51 return cast<CharacterLiteral>(Left)->getValue() ==
52 cast<CharacterLiteral>(Right)->getValue();
53 case Stmt::IntegerLiteralClass: {
54 llvm::APInt LeftLit = cast<IntegerLiteral>(Left)->getValue();
55 llvm::APInt RightLit = cast<IntegerLiteral>(Right)->getValue();
56 return LeftLit.getBitWidth() == RightLit.getBitWidth() && LeftLit == RightLit;
57 }
58 case Stmt::FloatingLiteralClass:
59 return cast<FloatingLiteral>(Left)->getValue().bitwiseIsEqual(
60 cast<FloatingLiteral>(Right)->getValue());
61 case Stmt::StringLiteralClass:
62 return cast<StringLiteral>(Left)->getBytes() ==
63 cast<StringLiteral>(Right)->getBytes();
64
65 case Stmt::DeclRefExprClass:
66 return cast<DeclRefExpr>(Left)->getDecl() ==
67 cast<DeclRefExpr>(Right)->getDecl();
68 case Stmt::MemberExprClass:
69 return cast<MemberExpr>(Left)->getMemberDecl() ==
70 cast<MemberExpr>(Right)->getMemberDecl();
71
72 case Stmt::CStyleCastExprClass:
73 return cast<CStyleCastExpr>(Left)->getTypeAsWritten() ==
74 cast<CStyleCastExpr>(Right)->getTypeAsWritten();
75
76 case Stmt::CallExprClass:
77 case Stmt::ImplicitCastExprClass:
78 case Stmt::ArraySubscriptExprClass:
79 return true;
80
81 case Stmt::UnaryOperatorClass:
82 if (cast<UnaryOperator>(Left)->isIncrementDecrementOp())
83 return false;
84 return cast<UnaryOperator>(Left)->getOpcode() ==
85 cast<UnaryOperator>(Right)->getOpcode();
86 case Stmt::BinaryOperatorClass:
87 return cast<BinaryOperator>(Left)->getOpcode() ==
88 cast<BinaryOperator>(Right)->getOpcode();
89 }
90}
91
92AST_MATCHER(BinaryOperator, OperandsAreEquivalent) {
93 return AreIdenticalExpr(Node.getLHS(), Node.getRHS());
94}
95
96AST_MATCHER(BinaryOperator, isInMacro) {
97 return Node.getOperatorLoc().isMacroID();
98}
99
100AST_MATCHER(Expr, isInstantiationDependent) {
101 return Node.isInstantiationDependent();
102}
103
104void RedundantExpressionCheck::registerMatchers(MatchFinder *Finder) {
105 const auto AnyLiteralExpr = ignoringParenImpCasts(
106 anyOf(cxxBoolLiteral(), characterLiteral(), integerLiteral()));
107
108 Finder->addMatcher(
109 binaryOperator(anyOf(hasOperatorName("-"), hasOperatorName("/"),
110 hasOperatorName("%"), hasOperatorName("|"),
111 hasOperatorName("&"), hasOperatorName("^"),
112 matchers::isComparisonOperator(),
113 hasOperatorName("&&"), hasOperatorName("||"),
114 hasOperatorName("=")),
115 OperandsAreEquivalent(),
116 // Filter noisy false positives.
117 unless(isInstantiationDependent()),
118 unless(isInMacro()),
119 unless(hasType(realFloatingPointType())),
120 unless(hasEitherOperand(hasType(realFloatingPointType()))),
121 unless(hasLHS(AnyLiteralExpr)))
122 .bind("binary"),
123 this);
124}
125
126void RedundantExpressionCheck::check(const MatchFinder::MatchResult &Result) {
127 if (const auto *BinOp = Result.Nodes.getNodeAs<BinaryOperator>("binary"))
128 diag(BinOp->getOperatorLoc(), "both side of operator are equivalent");
129}
130
131} // namespace misc
132} // namespace tidy
133} // namespace clang