23 const auto MakeBinaryOperatorMatcher = [](
auto Op) {
24 return [=](
const auto &LHS,
const auto &RHS) {
25 return binaryOperator(hasOperatorName(Op),
26 hasLHS(ignoringParenImpCasts(LHS)),
27 hasRHS(ignoringParenImpCasts(RHS)));
30 const auto MakeCommutativeBinaryOperatorMatcher = [](
auto Op) {
31 return [=](
const auto &LHS,
const auto &RHS) {
32 return binaryOperator(
34 hasOperands(ignoringParenImpCasts(LHS), ignoringParenImpCasts(RHS)));
38 const auto LogicalAnd = MakeCommutativeBinaryOperatorMatcher(
"&&");
39 const auto Sub = MakeBinaryOperatorMatcher(
"-");
40 const auto BitwiseAnd = MakeCommutativeBinaryOperatorMatcher(
"&");
41 const auto CmpNot = MakeCommutativeBinaryOperatorMatcher(
"!=");
42 const auto CmpGt = MakeBinaryOperatorMatcher(
">");
43 const auto CmpGte = MakeBinaryOperatorMatcher(
">=");
44 const auto CmpLt = MakeBinaryOperatorMatcher(
"<");
45 const auto CmpLte = MakeBinaryOperatorMatcher(
"<=");
47 const auto Literal0 = integerLiteral(equals(0));
48 const auto Literal1 = integerLiteral(equals(1));
50 const auto LogicalNot = [](
const auto &Expr) {
51 return unaryOperator(hasOperatorName(
"!"),
52 hasUnaryOperand(ignoringParenImpCasts(Expr)));
55 const auto IsNonNull = [=](
const auto &Expr) {
56 return anyOf(Expr, CmpNot(Expr, Literal0), CmpGt(Expr, Literal0),
57 CmpGte(Expr, Literal1), CmpLt(Literal0, Expr),
58 CmpLte(Literal1, Expr));
60 const auto BindDeclRef = [](StringRef Name) {
62 to(varDecl(hasType(isUnsignedInteger())).bind(Name.str())));
64 const auto BoundDeclRef = [](StringRef Name) {
65 return declRefExpr(to(varDecl(equalsBoundNode(Name.str()))));
71 LogicalAnd(IsNonNull(BindDeclRef(
"v")),
72 LogicalNot(BitwiseAnd(
74 Sub(BoundDeclRef(
"v"), integerLiteral(equals(1))))))
90 const ASTContext &Context = *Result.Context;
91 const SourceManager &Source = Context.getSourceManager();
93 const auto *MatchedVarDecl = Result.Nodes.getNodeAs<VarDecl>(
"v");
94 const auto *MatchedExpr = Result.Nodes.getNodeAs<BinaryOperator>(
"expr");
97 diag(MatchedExpr->getBeginLoc(),
"use 'std::has_one_bit' instead");
98 if (
auto R = MatchedExpr->getSourceRange();
99 !R.getBegin().isMacroID() && !R.getEnd().isMacroID()) {
100 Diag << FixItHint::CreateReplacement(
101 MatchedExpr->getSourceRange(),
102 (
"std::has_one_bit(" + MatchedVarDecl->getName() +
")").str())
103 << IncludeInserter.createIncludeInsertion(
104 Source.getFileID(MatchedExpr->getBeginLoc()),
"<bit>");
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.