[TargetVersion] Only enable on RISC-V and AArch64 (#115991)
[llvm-project.git] / clang-tools-extra / clang-tidy / readability / AvoidUnconditionalPreprocessorIfCheck.cpp
blobca5fc358ce290a2697896c95d14534dce4598417
1 //===--- AvoidUnconditionalPreprocessorIfCheck.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 //===----------------------------------------------------------------------===//
9 #include "AvoidUnconditionalPreprocessorIfCheck.h"
10 #include "clang/AST/ASTContext.h"
11 #include "clang/Lex/PPCallbacks.h"
12 #include "clang/Lex/Preprocessor.h"
14 using namespace clang::ast_matchers;
16 namespace clang::tidy::readability {
18 namespace {
19 struct AvoidUnconditionalPreprocessorIfPPCallbacks : public PPCallbacks {
21 explicit AvoidUnconditionalPreprocessorIfPPCallbacks(ClangTidyCheck &Check,
22 Preprocessor &PP)
23 : Check(Check), PP(PP) {}
25 void If(SourceLocation Loc, SourceRange ConditionRange,
26 ConditionValueKind ConditionValue) override {
27 if (ConditionValue == CVK_NotEvaluated)
28 return;
29 SourceManager &SM = PP.getSourceManager();
30 if (!isImmutable(SM, PP.getLangOpts(), ConditionRange))
31 return;
33 if (ConditionValue == CVK_True)
34 Check.diag(Loc, "preprocessor condition is always 'true', consider "
35 "removing condition but leaving its contents");
36 else
37 Check.diag(Loc, "preprocessor condition is always 'false', consider "
38 "removing both the condition and its contents");
41 bool isImmutable(SourceManager &SM, const LangOptions &LangOpts,
42 SourceRange ConditionRange) {
43 SourceLocation Loc = ConditionRange.getBegin();
44 if (Loc.isMacroID())
45 return false;
47 Token Tok;
48 if (Lexer::getRawToken(Loc, Tok, SM, LangOpts, true)) {
49 std::optional<Token> TokOpt = Lexer::findNextToken(Loc, SM, LangOpts);
50 if (!TokOpt || TokOpt->getLocation().isMacroID())
51 return false;
52 Tok = *TokOpt;
55 while (Tok.getLocation() <= ConditionRange.getEnd()) {
56 if (!isImmutableToken(Tok))
57 return false;
59 std::optional<Token> TokOpt =
60 Lexer::findNextToken(Tok.getLocation(), SM, LangOpts);
61 if (!TokOpt || TokOpt->getLocation().isMacroID())
62 return false;
63 Tok = *TokOpt;
66 return true;
69 bool isImmutableToken(const Token &Tok) {
70 switch (Tok.getKind()) {
71 case tok::eod:
72 case tok::eof:
73 case tok::numeric_constant:
74 case tok::char_constant:
75 case tok::wide_char_constant:
76 case tok::utf8_char_constant:
77 case tok::utf16_char_constant:
78 case tok::utf32_char_constant:
79 case tok::string_literal:
80 case tok::wide_string_literal:
81 case tok::comment:
82 return true;
83 case tok::raw_identifier:
84 return (Tok.getRawIdentifier() == "true" ||
85 Tok.getRawIdentifier() == "false");
86 default:
87 return Tok.getKind() >= tok::l_square &&
88 Tok.getKind() <= tok::greatergreatergreater;
92 ClangTidyCheck &Check;
93 Preprocessor &PP;
96 } // namespace
98 void AvoidUnconditionalPreprocessorIfCheck::registerPPCallbacks(
99 const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) {
100 PP->addPPCallbacks(
101 std::make_unique<AvoidUnconditionalPreprocessorIfPPCallbacks>(*this,
102 *PP));
105 } // namespace clang::tidy::readability