Skip to content

Commit ff0e538

Browse files
Vladislav Aranovearavla
authored andcommitted
[clang-tidy] Address false positives in misc-redundant-expression checker
Address situations when misc-redundant-expression checker provides excessive diagnostics for situations with different macros having the same value. In perticular situations described in the initial report of #118885 are addressed. The situations which are popped inside discussion like if (A + B == B + A) for macros are not properly addressed by this patch. But I still believe even in the current state the patch can be useful.
1 parent b7a6e9d commit ff0e538

File tree

2 files changed

+333
-24
lines changed

2 files changed

+333
-24
lines changed

clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp

Lines changed: 140 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -139,10 +139,8 @@ static bool areEquivalentExpr(const Expr *Left, const Expr *Right) {
139139
return cast<BinaryOperator>(Left)->getOpcode() ==
140140
cast<BinaryOperator>(Right)->getOpcode();
141141
case Stmt::UnaryExprOrTypeTraitExprClass:
142-
const auto *LeftUnaryExpr =
143-
cast<UnaryExprOrTypeTraitExpr>(Left);
144-
const auto *RightUnaryExpr =
145-
cast<UnaryExprOrTypeTraitExpr>(Right);
142+
const auto *LeftUnaryExpr = cast<UnaryExprOrTypeTraitExpr>(Left);
143+
const auto *RightUnaryExpr = cast<UnaryExprOrTypeTraitExpr>(Right);
146144
if (LeftUnaryExpr->isArgumentType() && RightUnaryExpr->isArgumentType())
147145
return LeftUnaryExpr->getKind() == RightUnaryExpr->getKind() &&
148146
LeftUnaryExpr->getArgumentType() ==
@@ -699,7 +697,8 @@ static bool retrieveRelationalIntegerConstantExpr(
699697

700698
Symbol = OverloadedOperatorExpr->getArg(IntegerConstantIsFirstArg ? 1 : 0);
701699
OperandExpr = OverloadedOperatorExpr;
702-
Opcode = BinaryOperator::getOverloadedOpcode(OverloadedOperatorExpr->getOperator());
700+
Opcode = BinaryOperator::getOverloadedOpcode(
701+
OverloadedOperatorExpr->getOperator());
703702

704703
if (!retrieveIntegerConstantExpr(Result, Id, Value, ConstExpr))
705704
return false;
@@ -728,7 +727,8 @@ static bool retrieveRelationalIntegerConstantExpr(
728727
}
729728

730729
// Checks for expressions like (X == 4) && (Y != 9)
731-
static bool areSidesBinaryConstExpressions(const BinaryOperator *&BinOp, const ASTContext *AstCtx) {
730+
static bool areSidesBinaryConstExpressions(const BinaryOperator *&BinOp,
731+
const ASTContext *AstCtx) {
732732
const auto *LhsBinOp = dyn_cast<BinaryOperator>(BinOp->getLHS());
733733
const auto *RhsBinOp = dyn_cast<BinaryOperator>(BinOp->getRHS());
734734

@@ -747,6 +747,28 @@ static bool areSidesBinaryConstExpressions(const BinaryOperator *&BinOp, const A
747747
return false;
748748
}
749749

750+
static bool areSidesBinaryConstExpressionsOrDefinesOrIntegerConstant(
751+
const BinaryOperator *&BinOp, const ASTContext *AstCtx) {
752+
if (areSidesBinaryConstExpressions(BinOp, AstCtx))
753+
return true;
754+
755+
const Expr *Lhs = BinOp->getLHS();
756+
const Expr *Rhs = BinOp->getRHS();
757+
758+
if (!Lhs || !Rhs)
759+
return false;
760+
761+
auto IsDefineExpr = [AstCtx](const Expr *E) {
762+
const SourceRange Lsr = E->getSourceRange();
763+
if (!Lsr.getBegin().isMacroID() || E->isValueDependent() ||
764+
!E->isIntegerConstantExpr(*AstCtx))
765+
return false;
766+
return true;
767+
};
768+
769+
return IsDefineExpr(Lhs) || IsDefineExpr(Rhs);
770+
}
771+
750772
// Retrieves integer constant subexpressions from binary operator expressions
751773
// that have two equivalent sides.
752774
// E.g.: from (X == 5) && (X == 5) retrieves 5 and 5.
@@ -785,7 +807,7 @@ static bool retrieveConstExprFromBothSides(const BinaryOperator *&BinOp,
785807
}
786808

787809
static bool isSameRawIdentifierToken(const Token &T1, const Token &T2,
788-
const SourceManager &SM) {
810+
const SourceManager &SM) {
789811
if (T1.getKind() != T2.getKind())
790812
return false;
791813
if (T1.isNot(tok::raw_identifier))
@@ -808,8 +830,8 @@ static bool areExprsFromDifferentMacros(const Expr *LhsExpr,
808830
const ASTContext *AstCtx) {
809831
if (!LhsExpr || !RhsExpr)
810832
return false;
811-
SourceRange Lsr = LhsExpr->getSourceRange();
812-
SourceRange Rsr = RhsExpr->getSourceRange();
833+
const SourceRange Lsr = LhsExpr->getSourceRange();
834+
const SourceRange Rsr = RhsExpr->getSourceRange();
813835
if (!Lsr.getBegin().isMacroID() || !Rsr.getBegin().isMacroID())
814836
return false;
815837

@@ -847,11 +869,102 @@ static bool areExprsMacroAndNonMacro(const Expr *&LhsExpr,
847869
if (!LhsExpr || !RhsExpr)
848870
return false;
849871

850-
SourceLocation LhsLoc = LhsExpr->getExprLoc();
851-
SourceLocation RhsLoc = RhsExpr->getExprLoc();
872+
const SourceLocation LhsLoc = LhsExpr->getExprLoc();
873+
const SourceLocation RhsLoc = RhsExpr->getExprLoc();
852874

853875
return LhsLoc.isMacroID() != RhsLoc.isMacroID();
854876
}
877+
878+
static bool areStringsSameIgnoreSpaces(const llvm::StringRef *Left,
879+
const llvm::StringRef *Right) {
880+
if (Left == Right)
881+
return true;
882+
if (Left->compare(*Right) == 0) {
883+
return true;
884+
}
885+
// Do running index comparison
886+
size_t LIdx = 0;
887+
size_t RIdx = 0;
888+
const char *LData = Left->data();
889+
const char *RData = Right->data();
890+
while (LIdx < Left->size() && RIdx < Right->size()) {
891+
while (LIdx < Left->size() && (LData[LIdx] == ' ' || LData[LIdx] == '\t')) {
892+
LIdx++;
893+
}
894+
while (RIdx < Right->size() &&
895+
(RData[RIdx] == ' ' || RData[RIdx] == '\t')) {
896+
RIdx++;
897+
}
898+
899+
// If all not tabs and spaces are the same then return true
900+
if (LIdx == Left->size() && RIdx == Right->size())
901+
return true;
902+
903+
// If any characters differs then return false
904+
else if (LData[LIdx] != RData[RIdx])
905+
return false;
906+
907+
// If current char is the same ==> continue search
908+
else {
909+
LIdx += 1;
910+
RIdx += 1;
911+
}
912+
}
913+
// If we reach here then we have real length difference
914+
return LIdx == Left->size() && RIdx == Right->size();
915+
}
916+
917+
static bool areExprsSameMacroOrLiteral(const BinaryOperator *BinOp,
918+
const ASTContext *Context) {
919+
920+
if (!BinOp)
921+
return false;
922+
923+
const Expr *Lhs = BinOp->getLHS();
924+
const Expr *Rhs = BinOp->getRHS();
925+
const SourceManager &SM = Context->getSourceManager();
926+
927+
const SourceRange Lsr = Lhs->getSourceRange();
928+
const SourceRange Rsr = Rhs->getSourceRange();
929+
if (Lsr.getBegin().isMacroID()) {
930+
// Left is macro so right macro too
931+
if (Rsr.getBegin().isMacroID()) {
932+
// Both sides are macros so they are same macro or literal
933+
llvm::StringRef L = Lexer::getSourceText(
934+
CharSourceRange::getTokenRange(Lsr), SM, LangOptions(), 0);
935+
llvm::StringRef R = Lexer::getSourceText(
936+
CharSourceRange::getTokenRange(Rsr), SM, LangOptions(), 0);
937+
return areStringsSameIgnoreSpaces(&L, &R);
938+
}
939+
// Left is macro but right is not so they are not same macro or literal
940+
return false;
941+
} else {
942+
const auto *Lil = dyn_cast<IntegerLiteral>(Lhs);
943+
const auto *Ril = dyn_cast<IntegerLiteral>(Rhs);
944+
if (Lil && Ril) {
945+
return Lil->getValue() == Ril->getValue();
946+
}
947+
948+
const auto *LStrl = dyn_cast<StringLiteral>(Lhs);
949+
const auto *RStrl = dyn_cast<StringLiteral>(Rhs);
950+
if (Lil && Ril) {
951+
llvm::StringRef L = Lexer::getSourceText(
952+
CharSourceRange::getTokenRange(LStrl->getBeginLoc()), SM,
953+
LangOptions(), 0);
954+
llvm::StringRef R = Lexer::getSourceText(
955+
CharSourceRange::getTokenRange(RStrl->getBeginLoc()), SM,
956+
LangOptions(), 0);
957+
return L.compare(R) == 0;
958+
}
959+
960+
const auto *Lbl = dyn_cast<CXXBoolLiteralExpr>(Lhs);
961+
const auto *Rbl = dyn_cast<CXXBoolLiteralExpr>(Rhs);
962+
if (Lbl && Rbl) {
963+
return Lbl->getValue() == Rbl->getValue();
964+
}
965+
}
966+
return false;
967+
}
855968
} // namespace
856969

857970
void RedundantExpressionCheck::registerMatchers(MatchFinder *Finder) {
@@ -1089,7 +1202,6 @@ static bool exprEvaluatesToSymbolic(BinaryOperatorKind Opcode, APSInt Value) {
10891202
((Opcode == BO_And || Opcode == BO_AndAssign) && ~Value == 0);
10901203
}
10911204

1092-
10931205
void RedundantExpressionCheck::checkBitwiseExpr(
10941206
const MatchFinder::MatchResult &Result) {
10951207
if (const auto *ComparisonOperator = Result.Nodes.getNodeAs<BinaryOperator>(
@@ -1134,8 +1246,8 @@ void RedundantExpressionCheck::checkBitwiseExpr(
11341246
ConstExpr))
11351247
return;
11361248

1137-
if((Value != 0 && ~Value != 0) || Sym->getExprLoc().isMacroID())
1138-
return;
1249+
if ((Value != 0 && ~Value != 0) || Sym->getExprLoc().isMacroID())
1250+
return;
11391251

11401252
SourceLocation Loc = IneffectiveOperator->getOperatorLoc();
11411253

@@ -1276,19 +1388,23 @@ void RedundantExpressionCheck::check(const MatchFinder::MatchResult &Result) {
12761388
return;
12771389
}
12781390

1279-
if (areSidesBinaryConstExpressions(BinOp, Result.Context)) {
1391+
if (areSidesBinaryConstExpressionsOrDefinesOrIntegerConstant(
1392+
BinOp, Result.Context)) {
12801393
const Expr *LhsConst = nullptr, *RhsConst = nullptr;
12811394
BinaryOperatorKind MainOpcode{}, SideOpcode{};
1282-
1283-
if (!retrieveConstExprFromBothSides(BinOp, MainOpcode, SideOpcode,
1284-
LhsConst, RhsConst, Result.Context))
1285-
return;
1286-
1287-
if (areExprsFromDifferentMacros(LhsConst, RhsConst, Result.Context) ||
1288-
areExprsMacroAndNonMacro(LhsConst, RhsConst))
1289-
return;
1395+
if (areSidesBinaryConstExpressions(BinOp, Result.Context)) {
1396+
if (!retrieveConstExprFromBothSides(BinOp, MainOpcode, SideOpcode,
1397+
LhsConst, RhsConst, Result.Context))
1398+
return;
1399+
1400+
if (areExprsFromDifferentMacros(LhsConst, RhsConst, Result.Context) ||
1401+
areExprsMacroAndNonMacro(LhsConst, RhsConst))
1402+
return;
1403+
} else {
1404+
if (!areExprsSameMacroOrLiteral(BinOp, Result.Context))
1405+
return;
1406+
}
12901407
}
1291-
12921408
diag(BinOp->getOperatorLoc(), "both sides of operator are equivalent");
12931409
}
12941410

0 commit comments

Comments
 (0)