clang-tools 22.0.0git
AvoidUnconditionalPreprocessorIfCheck.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
10#include "../utils/LexerUtils.h"
11#include "clang/AST/ASTContext.h"
12#include "clang/Lex/PPCallbacks.h"
13#include "clang/Lex/Preprocessor.h"
14
15using namespace clang::ast_matchers;
16
18
19namespace {
20struct AvoidUnconditionalPreprocessorIfPPCallbacks : public PPCallbacks {
21 explicit AvoidUnconditionalPreprocessorIfPPCallbacks(ClangTidyCheck &Check,
22 Preprocessor &PP)
23 : Check(Check), PP(PP) {}
24
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;
32
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");
39 }
40
41 bool isImmutable(SourceManager &SM, const LangOptions &LangOpts,
42 SourceRange ConditionRange) {
43 const SourceLocation Loc = ConditionRange.getBegin();
44 if (Loc.isMacroID())
45 return false;
46
47 Token Tok;
48 if (Lexer::getRawToken(Loc, Tok, SM, LangOpts, true)) {
49 std::optional<Token> TokOpt =
51 if (!TokOpt || TokOpt->getLocation().isMacroID())
52 return false;
53 Tok = *TokOpt;
54 }
55
56 while (Tok.getLocation() <= ConditionRange.getEnd()) {
57 if (!isImmutableToken(Tok))
58 return false;
59
60 std::optional<Token> TokOpt = utils::lexer::findNextTokenSkippingComments(
61 Tok.getLocation(), SM, LangOpts);
62 if (!TokOpt || TokOpt->getLocation().isMacroID())
63 return false;
64 Tok = *TokOpt;
65 }
66
67 return true;
68 }
69
70 bool isImmutableToken(const Token &Tok) {
71 switch (Tok.getKind()) {
72 case tok::eod:
73 case tok::eof:
74 case tok::numeric_constant:
75 case tok::char_constant:
76 case tok::wide_char_constant:
77 case tok::utf8_char_constant:
78 case tok::utf16_char_constant:
79 case tok::utf32_char_constant:
80 case tok::string_literal:
81 case tok::wide_string_literal:
82 case tok::comment:
83 return true;
84 case tok::raw_identifier:
85 return (Tok.getRawIdentifier() == "true" ||
86 Tok.getRawIdentifier() == "false");
87 default:
88 return Tok.getKind() >= tok::l_square &&
89 Tok.getKind() <= tok::greatergreatergreater;
90 }
91 }
92
93 ClangTidyCheck &Check;
94 Preprocessor &PP;
95};
96
97} // namespace
98
100 const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) {
101 PP->addPPCallbacks(
102 std::make_unique<AvoidUnconditionalPreprocessorIfPPCallbacks>(*this,
103 *PP));
104}
105
106} // namespace clang::tidy::readability
void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) override
std::optional< Token > findNextTokenSkippingComments(SourceLocation Start, const SourceManager &SM, const LangOptions &LangOpts)
Definition LexerUtils.h:101