[clang-tools-extra] [clang-tidy] New checker: modernize.use-std-bit to detect std::has_one_bit idiom (PR #185435)
Yanzuo Liu via cfe-commits
cfe-commits at lists.llvm.org
Mon Mar 9 10:31:46 PDT 2026
================
@@ -0,0 +1,84 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "UseStdBitCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::modernize {
+
+void UseStdBitCheck::registerMatchers(MatchFinder *Finder) {
+ const auto MakeBinaryOperatorMatcher = [](auto Op) {
+ return [=](const auto &LHS, const auto &RHS) {
+ return binaryOperator(
+ hasOperatorName(Op),
+ hasOperands(ignoringParenImpCasts(LHS), ignoringParenImpCasts(RHS)));
+ };
+ };
+
+ const auto LogicalAnd = MakeBinaryOperatorMatcher("&&");
+ const auto Sub = MakeBinaryOperatorMatcher("-");
+ const auto BitwiseAnd = MakeBinaryOperatorMatcher("&");
+ const auto CmpNot = MakeBinaryOperatorMatcher("!=");
+ const auto CmpGt = MakeBinaryOperatorMatcher(">");
+
+ const auto LogicalNot = [](const auto &Expr) {
+ return unaryOperator(hasOperatorName("!"),
+ hasUnaryOperand(ignoringParenImpCasts(Expr)));
+ };
+
+ const auto IsNonNull = [=](const auto &Expr) {
+ return anyOf(Expr, CmpNot(Expr, integerLiteral(equals(0))),
+ CmpGt(Expr, integerLiteral(equals(0))));
+ };
+ const auto BindDeclRef = [](auto Name) {
+ return declRefExpr(to(varDecl(hasType(isUnsignedInteger())).bind(Name)));
+ };
+ const auto BoundDeclRef = [](auto Name) {
+ return declRefExpr(to(varDecl(equalsBoundNode(Name))));
+ };
+
+ // https://graphics.stanford.edu/~seander/bithacks.html#DetermineIfPowerOf2
+ // has_one_bit(v) = v && !(v & (v - 1));
+ Finder->addMatcher(
+ LogicalAnd(IsNonNull(BindDeclRef("v")),
+ LogicalNot(BitwiseAnd(
+ BoundDeclRef("v"),
+ Sub(BoundDeclRef("v"), integerLiteral(equals(1))))))
+ .bind("expr"),
+ this);
+}
+
+void UseStdBitCheck::registerPPCallbacks(const SourceManager &SM,
+ Preprocessor *PP,
+ Preprocessor *ModuleExpanderPP) {
+ IncludeInserter.registerPreprocessor(PP);
+}
+
+void UseStdBitCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "IncludeStyle", IncludeInserter.getStyle());
+}
+
+void UseStdBitCheck::check(const MatchFinder::MatchResult &Result) {
+ const ASTContext &Context = *Result.Context;
+ const SourceManager &Source = Context.getSourceManager();
+
+ const auto *MatchedVarDecl = Result.Nodes.getNodeAs<VarDecl>("v");
+ const auto *MatchedExpr = Result.Nodes.getNodeAs<BinaryOperator>("expr");
+
+ diag(MatchedExpr->getBeginLoc(), "use std::has_one_bit instead")
+ << MatchedVarDecl->getName()
----------------
zwuis wrote:
Redundant output?
https://github.com/llvm/llvm-project/pull/185435
More information about the cfe-commits
mailing list