25 const auto MakeBinaryOperatorMatcher = [](
auto Op) {
26 return [=](
const auto &LHS,
const auto &RHS) {
27 return binaryOperator(hasOperatorName(Op),
28 hasLHS(ignoringParenImpCasts(LHS)),
29 hasRHS(ignoringParenImpCasts(RHS)));
32 const auto MakeCommutativeBinaryOperatorMatcher = [](
auto Op) {
33 return [=](
const auto &LHS,
const auto &RHS) {
34 return binaryOperator(
36 hasOperands(ignoringParenImpCasts(LHS), ignoringParenImpCasts(RHS)));
40 const auto LogicalAnd = MakeCommutativeBinaryOperatorMatcher(
"&&");
41 const auto Sub = MakeBinaryOperatorMatcher(
"-");
42 const auto ShiftLeft = MakeBinaryOperatorMatcher(
"<<");
43 const auto ShiftRight = MakeBinaryOperatorMatcher(
">>");
44 const auto BitwiseAnd = MakeCommutativeBinaryOperatorMatcher(
"&");
45 const auto BitwiseOr = MakeCommutativeBinaryOperatorMatcher(
"|");
46 const auto CmpNot = MakeCommutativeBinaryOperatorMatcher(
"!=");
47 const auto CmpGt = MakeBinaryOperatorMatcher(
">");
48 const auto CmpGte = MakeBinaryOperatorMatcher(
">=");
49 const auto CmpLt = MakeBinaryOperatorMatcher(
"<");
50 const auto CmpLte = MakeBinaryOperatorMatcher(
"<=");
52 const auto Literal0 = integerLiteral(equals(0));
53 const auto Literal1 = integerLiteral(equals(1));
55 const auto LogicalNot = [](
const auto &Expr) {
56 return unaryOperator(hasOperatorName(
"!"),
57 hasUnaryOperand(ignoringParenImpCasts(Expr)));
60 const auto IsNonNull = [=](
const auto &Expr) {
61 return anyOf(Expr, CmpNot(Expr, Literal0), CmpGt(Expr, Literal0),
62 CmpGte(Expr, Literal1), CmpLt(Literal0, Expr),
63 CmpLte(Literal1, Expr));
65 const auto BindDeclRef = [](StringRef Name) {
67 to(varDecl(hasType(isUnsignedInteger())).bind(Name.str())));
69 const auto BoundDeclRef = [](StringRef Name) {
70 return declRefExpr(to(varDecl(equalsBoundNode(Name.str()))));
76 LogicalAnd(IsNonNull(BindDeclRef(
"v")),
77 LogicalNot(BitwiseAnd(
79 Sub(BoundDeclRef(
"v"), integerLiteral(equals(1))))))
80 .bind(
"has_one_bit_expr"),
90 ofClass(cxxRecordDecl(hasName(
"bitset"), isInStdNamespace())))),
92 hasArgument(0, expr(hasType(isUnsignedInteger())).bind(
"v")))))
93 .bind(
"popcount_expr"),
98 expr(BitwiseOr(ShiftLeft(BindDeclRef(
"v"),
99 integerLiteral().bind(
"shift_left_amount")),
100 ShiftRight(BoundDeclRef(
"v"),
101 integerLiteral().bind(
"shift_right_amount"))),
102 optionally(hasParent(castExpr(hasType(isInteger())).bind(
"cast"))))
103 .bind(
"rotate_expr"),
119 ASTContext &Context = *Result.Context;
120 const SourceManager &Source = Context.getSourceManager();
122 if (
const auto *MatchedExpr =
123 Result.Nodes.getNodeAs<BinaryOperator>(
"has_one_bit_expr")) {
124 const auto *MatchedVarDecl = Result.Nodes.getNodeAs<VarDecl>(
"v");
127 diag(MatchedExpr->getBeginLoc(),
"use 'std::has_one_bit' instead");
128 if (
auto R = MatchedExpr->getSourceRange();
129 !R.getBegin().isMacroID() && !R.getEnd().isMacroID()) {
130 Diag << FixItHint::CreateReplacement(
131 MatchedExpr->getSourceRange(),
132 (
"std::has_one_bit(" + MatchedVarDecl->getName() +
")").str())
133 << IncludeInserter.createIncludeInsertion(
134 Source.getFileID(MatchedExpr->getBeginLoc()),
"<bit>");
136 }
else if (
const auto *MatchedExpr =
137 Result.Nodes.getNodeAs<CXXMemberCallExpr>(
"popcount_expr")) {
138 const auto *BitsetInstantiatedDecl =
139 cast<ClassTemplateSpecializationDecl>(MatchedExpr->getRecordDecl());
140 const llvm::APSInt BitsetSize =
141 BitsetInstantiatedDecl->getTemplateArgs()[0].getAsIntegral();
142 const auto *MatchedArg = Result.Nodes.getNodeAs<Expr>(
"v");
143 const uint64_t MatchedVarSize = Context.getTypeSize(MatchedArg->getType());
144 if (BitsetSize < MatchedVarSize)
146 auto Diag = diag(MatchedExpr->getBeginLoc(),
"use 'std::popcount' instead");
147 if (
auto R = MatchedExpr->getSourceRange();
148 !R.getBegin().isMacroID() && !R.getEnd().isMacroID()) {
149 Diag << FixItHint::CreateRemoval(CharSourceRange::getTokenRange(
150 MatchedArg->getEndLoc().getLocWithOffset(1),
151 MatchedExpr->getRParenLoc().getLocWithOffset(-1)))
152 << FixItHint::CreateReplacement(
153 CharSourceRange::getTokenRange(
154 MatchedExpr->getBeginLoc(),
155 MatchedArg->getBeginLoc().getLocWithOffset(-1)),
157 << IncludeInserter.createIncludeInsertion(
158 Source.getFileID(MatchedExpr->getBeginLoc()),
"<bit>");
160 }
else if (
const auto *MatchedExpr =
161 Result.Nodes.getNodeAs<Expr>(
"rotate_expr")) {
165 bool HasExplicitIntegerCast =
false;
166 if (
const Expr *CE = Result.Nodes.getNodeAs<CastExpr>(
"cast"))
167 HasExplicitIntegerCast = !isa<ImplicitCastExpr>(CE);
169 const auto *MatchedVarDecl = Result.Nodes.getNodeAs<VarDecl>(
"v");
170 const llvm::APInt ShiftLeftAmount =
171 Result.Nodes.getNodeAs<IntegerLiteral>(
"shift_left_amount")->getValue();
172 const llvm::APInt ShiftRightAmount =
173 Result.Nodes.getNodeAs<IntegerLiteral>(
"shift_right_amount")
175 const uint64_t MatchedVarSize =
176 Context.getTypeSize(MatchedVarDecl->getType());
179 if (ShiftLeftAmount.sge(MatchedVarSize))
181 if (ShiftRightAmount.sge(MatchedVarSize))
184 if (MatchedVarSize != (ShiftLeftAmount + ShiftRightAmount))
189 const bool NeedsIntCast =
190 HonorIntPromotion && !HasExplicitIntegerCast &&
191 Context.getTypeSize(MatchedExpr->getType()) > MatchedVarSize;
192 const bool IsRotl = ShiftRightAmount.sge(ShiftLeftAmount);
194 const StringRef ReplacementFuncName = IsRotl ?
"rotl" :
"rotr";
195 const uint64_t ReplacementShiftAmount =
196 (IsRotl ? ShiftLeftAmount : ShiftRightAmount).getZExtValue();
197 auto Diag = diag(MatchedExpr->getBeginLoc(),
"use 'std::%0' instead")
198 << ReplacementFuncName;
199 if (
auto R = MatchedExpr->getSourceRange();
200 R.getBegin().isMacroID() || R.getEnd().isMacroID())
203 Diag << FixItHint::CreateReplacement(
204 MatchedExpr->getSourceRange(),
205 llvm::formatv(
"{3}std::{0}({1}, {2}){4}", ReplacementFuncName,
206 MatchedVarDecl->getName(), ReplacementShiftAmount,
207 NeedsIntCast ?
"static_cast<int>(" :
"",
208 NeedsIntCast ?
")" :
"")
210 << IncludeInserter.createIncludeInsertion(
211 Source.getFileID(MatchedExpr->getBeginLoc()),
"<bit>");
214 llvm_unreachable(
"unexpected match");
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.