1 | //===--- UseBoolLiteralsCheck.cpp - clang-tidy-----------------------------===// |
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 "UseBoolLiteralsCheck.h" |
10 | #include "clang/AST/ASTContext.h" |
11 | #include "clang/ASTMatchers/ASTMatchFinder.h" |
12 | #include "clang/Lex/Lexer.h" |
13 | |
14 | using namespace clang::ast_matchers; |
15 | |
16 | namespace clang::tidy::modernize { |
17 | |
18 | UseBoolLiteralsCheck::UseBoolLiteralsCheck(StringRef Name, |
19 | ClangTidyContext *Context) |
20 | : ClangTidyCheck(Name, Context), |
21 | IgnoreMacros(Options.getLocalOrGlobal(LocalName: "IgnoreMacros" , Default: true)) {} |
22 | |
23 | void UseBoolLiteralsCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { |
24 | Options.store(Options&: Opts, LocalName: "IgnoreMacros" , Value: IgnoreMacros); |
25 | } |
26 | |
27 | void UseBoolLiteralsCheck::registerMatchers(MatchFinder *Finder) { |
28 | Finder->addMatcher( |
29 | NodeMatch: traverse( |
30 | TK: TK_AsIs, |
31 | InnerMatcher: implicitCastExpr( |
32 | has(ignoringParenImpCasts(InnerMatcher: integerLiteral().bind(ID: "literal" ))), |
33 | hasImplicitDestinationType(InnerMatcher: qualType(booleanType())), |
34 | unless(isInTemplateInstantiation()), |
35 | anyOf(hasParent(explicitCastExpr().bind(ID: "cast" )), anything()))), |
36 | Action: this); |
37 | |
38 | Finder->addMatcher( |
39 | NodeMatch: traverse(TK: TK_AsIs, |
40 | InnerMatcher: conditionalOperator( |
41 | hasParent(implicitCastExpr( |
42 | hasImplicitDestinationType(InnerMatcher: qualType(booleanType())), |
43 | unless(isInTemplateInstantiation()))), |
44 | eachOf(hasTrueExpression(InnerMatcher: ignoringParenImpCasts( |
45 | InnerMatcher: integerLiteral().bind(ID: "literal" ))), |
46 | hasFalseExpression(InnerMatcher: ignoringParenImpCasts( |
47 | InnerMatcher: integerLiteral().bind(ID: "literal" )))))), |
48 | Action: this); |
49 | } |
50 | |
51 | void UseBoolLiteralsCheck::check(const MatchFinder::MatchResult &Result) { |
52 | const auto *Literal = Result.Nodes.getNodeAs<IntegerLiteral>(ID: "literal" ); |
53 | const auto *Cast = Result.Nodes.getNodeAs<Expr>(ID: "cast" ); |
54 | bool LiteralBooleanValue = Literal->getValue().getBoolValue(); |
55 | |
56 | if (Literal->isInstantiationDependent()) |
57 | return; |
58 | |
59 | const Expr *Expression = Cast ? Cast : Literal; |
60 | |
61 | bool InMacro = Expression->getBeginLoc().isMacroID(); |
62 | |
63 | if (InMacro && IgnoreMacros) |
64 | return; |
65 | |
66 | auto Diag = |
67 | diag(Loc: Expression->getExprLoc(), |
68 | Description: "converting integer literal to bool, use bool literal instead" ); |
69 | |
70 | if (!InMacro) |
71 | Diag << FixItHint::CreateReplacement( |
72 | Expression->getSourceRange(), LiteralBooleanValue ? "true" : "false" ); |
73 | } |
74 | |
75 | } // namespace clang::tidy::modernize |
76 | |