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