clang-tools 23.0.0git
UseStdBitCheck.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "UseStdBitCheck.h"
10#include "clang/ASTMatchers/ASTMatchFinder.h"
11
12using namespace clang::ast_matchers;
13
14namespace clang::tidy::modernize {
15
17 : ClangTidyCheck(Name, Context),
18 IncludeInserter(Options.getLocalOrGlobal("IncludeStyle",
19 utils::IncludeSorter::IS_LLVM),
20 areDiagsSelfContained()) {}
21
22void UseStdBitCheck::registerMatchers(MatchFinder *Finder) {
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)));
28 };
29 };
30 const auto MakeCommutativeBinaryOperatorMatcher = [](auto Op) {
31 return [=](const auto &LHS, const auto &RHS) {
32 return binaryOperator(
33 hasOperatorName(Op),
34 hasOperands(ignoringParenImpCasts(LHS), ignoringParenImpCasts(RHS)));
35 };
36 };
37
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("<=");
46
47 const auto Literal0 = integerLiteral(equals(0));
48 const auto Literal1 = integerLiteral(equals(1));
49
50 const auto LogicalNot = [](const auto &Expr) {
51 return unaryOperator(hasOperatorName("!"),
52 hasUnaryOperand(ignoringParenImpCasts(Expr)));
53 };
54
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));
59 };
60 const auto BindDeclRef = [](StringRef Name) {
61 return declRefExpr(
62 to(varDecl(hasType(isUnsignedInteger())).bind(Name.str())));
63 };
64 const auto BoundDeclRef = [](StringRef Name) {
65 return declRefExpr(to(varDecl(equalsBoundNode(Name.str()))));
66 };
67
68 // Determining if an integer is a power of 2 with following pattern:
69 // has_one_bit(v) = v && !(v & (v - 1));
70 Finder->addMatcher(
71 LogicalAnd(IsNonNull(BindDeclRef("v")),
72 LogicalNot(BitwiseAnd(
73 BoundDeclRef("v"),
74 Sub(BoundDeclRef("v"), integerLiteral(equals(1))))))
75 .bind("expr"),
76 this);
77}
78
79void UseStdBitCheck::registerPPCallbacks(const SourceManager &SM,
80 Preprocessor *PP,
81 Preprocessor *ModuleExpanderPP) {
82 IncludeInserter.registerPreprocessor(PP);
83}
84
86 Options.store(Opts, "IncludeStyle", IncludeInserter.getStyle());
87}
88
89void UseStdBitCheck::check(const MatchFinder::MatchResult &Result) {
90 const ASTContext &Context = *Result.Context;
91 const SourceManager &Source = Context.getSourceManager();
92
93 const auto *MatchedVarDecl = Result.Nodes.getNodeAs<VarDecl>("v");
94 const auto *MatchedExpr = Result.Nodes.getNodeAs<BinaryOperator>("expr");
95
96 auto Diag =
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>");
105 }
106}
107
108} // namespace clang::tidy::modernize
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
UseStdBitCheck(StringRef Name, ClangTidyContext *Context)
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
void registerMatchers(ast_matchers::MatchFinder *Finder) override
void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) override
llvm::StringMap< ClangTidyValue > OptionMap