152296f5eSPiotr Zegar //===--- AvoidUnconditionalPreprocessorIfCheck.cpp - clang-tidy -----------===// 252296f5eSPiotr Zegar // 352296f5eSPiotr Zegar // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 452296f5eSPiotr Zegar // See https://llvm.org/LICENSE.txt for license information. 552296f5eSPiotr Zegar // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 652296f5eSPiotr Zegar // 752296f5eSPiotr Zegar //===----------------------------------------------------------------------===// 852296f5eSPiotr Zegar 952296f5eSPiotr Zegar #include "AvoidUnconditionalPreprocessorIfCheck.h" 1052296f5eSPiotr Zegar #include "clang/AST/ASTContext.h" 1152296f5eSPiotr Zegar #include "clang/Lex/PPCallbacks.h" 1252296f5eSPiotr Zegar #include "clang/Lex/Preprocessor.h" 1352296f5eSPiotr Zegar 1452296f5eSPiotr Zegar using namespace clang::ast_matchers; 1552296f5eSPiotr Zegar 1652296f5eSPiotr Zegar namespace clang::tidy::readability { 1752296f5eSPiotr Zegar 1852296f5eSPiotr Zegar namespace { 1952296f5eSPiotr Zegar struct AvoidUnconditionalPreprocessorIfPPCallbacks : public PPCallbacks { 2052296f5eSPiotr Zegar 2152296f5eSPiotr Zegar explicit AvoidUnconditionalPreprocessorIfPPCallbacks(ClangTidyCheck &Check, 2252296f5eSPiotr Zegar Preprocessor &PP) 2352296f5eSPiotr Zegar : Check(Check), PP(PP) {} 2452296f5eSPiotr Zegar 2552296f5eSPiotr Zegar void If(SourceLocation Loc, SourceRange ConditionRange, 2652296f5eSPiotr Zegar ConditionValueKind ConditionValue) override { 2752296f5eSPiotr Zegar if (ConditionValue == CVK_NotEvaluated) 2852296f5eSPiotr Zegar return; 2952296f5eSPiotr Zegar SourceManager &SM = PP.getSourceManager(); 3052296f5eSPiotr Zegar if (!isImmutable(SM, PP.getLangOpts(), ConditionRange)) 3152296f5eSPiotr Zegar return; 3252296f5eSPiotr Zegar 3352296f5eSPiotr Zegar if (ConditionValue == CVK_True) 3452296f5eSPiotr Zegar Check.diag(Loc, "preprocessor condition is always 'true', consider " 3552296f5eSPiotr Zegar "removing condition but leaving its contents"); 3652296f5eSPiotr Zegar else 3752296f5eSPiotr Zegar Check.diag(Loc, "preprocessor condition is always 'false', consider " 3852296f5eSPiotr Zegar "removing both the condition and its contents"); 3952296f5eSPiotr Zegar } 4052296f5eSPiotr Zegar 4152296f5eSPiotr Zegar bool isImmutable(SourceManager &SM, const LangOptions &LangOpts, 4252296f5eSPiotr Zegar SourceRange ConditionRange) { 4352296f5eSPiotr Zegar SourceLocation Loc = ConditionRange.getBegin(); 4452296f5eSPiotr Zegar if (Loc.isMacroID()) 4552296f5eSPiotr Zegar return false; 4652296f5eSPiotr Zegar 4752296f5eSPiotr Zegar Token Tok; 4852296f5eSPiotr Zegar if (Lexer::getRawToken(Loc, Tok, SM, LangOpts, true)) { 4952296f5eSPiotr Zegar std::optional<Token> TokOpt = Lexer::findNextToken(Loc, SM, LangOpts); 5052296f5eSPiotr Zegar if (!TokOpt || TokOpt->getLocation().isMacroID()) 5152296f5eSPiotr Zegar return false; 5252296f5eSPiotr Zegar Tok = *TokOpt; 5352296f5eSPiotr Zegar } 5452296f5eSPiotr Zegar 5552296f5eSPiotr Zegar while (Tok.getLocation() <= ConditionRange.getEnd()) { 5652296f5eSPiotr Zegar if (!isImmutableToken(Tok)) 5752296f5eSPiotr Zegar return false; 5852296f5eSPiotr Zegar 5952296f5eSPiotr Zegar std::optional<Token> TokOpt = 6052296f5eSPiotr Zegar Lexer::findNextToken(Tok.getLocation(), SM, LangOpts); 6152296f5eSPiotr Zegar if (!TokOpt || TokOpt->getLocation().isMacroID()) 6252296f5eSPiotr Zegar return false; 6352296f5eSPiotr Zegar Tok = *TokOpt; 6452296f5eSPiotr Zegar } 6552296f5eSPiotr Zegar 6652296f5eSPiotr Zegar return true; 6752296f5eSPiotr Zegar } 6852296f5eSPiotr Zegar 6952296f5eSPiotr Zegar bool isImmutableToken(const Token &Tok) { 7052296f5eSPiotr Zegar switch (Tok.getKind()) { 7152296f5eSPiotr Zegar case tok::eod: 7252296f5eSPiotr Zegar case tok::eof: 7352296f5eSPiotr Zegar case tok::numeric_constant: 7452296f5eSPiotr Zegar case tok::char_constant: 7552296f5eSPiotr Zegar case tok::wide_char_constant: 7652296f5eSPiotr Zegar case tok::utf8_char_constant: 7752296f5eSPiotr Zegar case tok::utf16_char_constant: 7852296f5eSPiotr Zegar case tok::utf32_char_constant: 7952296f5eSPiotr Zegar case tok::string_literal: 8052296f5eSPiotr Zegar case tok::wide_string_literal: 8152296f5eSPiotr Zegar case tok::comment: 8252296f5eSPiotr Zegar return true; 8352296f5eSPiotr Zegar case tok::raw_identifier: 8452296f5eSPiotr Zegar return (Tok.getRawIdentifier() == "true" || 8552296f5eSPiotr Zegar Tok.getRawIdentifier() == "false"); 8652296f5eSPiotr Zegar default: 87*1881f648SAaron Ballman return Tok.getKind() >= tok::l_square && 88*1881f648SAaron Ballman Tok.getKind() <= tok::greatergreatergreater; 8952296f5eSPiotr Zegar } 9052296f5eSPiotr Zegar } 9152296f5eSPiotr Zegar 9252296f5eSPiotr Zegar ClangTidyCheck &Check; 9352296f5eSPiotr Zegar Preprocessor &PP; 9452296f5eSPiotr Zegar }; 9552296f5eSPiotr Zegar 9652296f5eSPiotr Zegar } // namespace 9752296f5eSPiotr Zegar 9852296f5eSPiotr Zegar void AvoidUnconditionalPreprocessorIfCheck::registerPPCallbacks( 9952296f5eSPiotr Zegar const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) { 10052296f5eSPiotr Zegar PP->addPPCallbacks( 10152296f5eSPiotr Zegar std::make_unique<AvoidUnconditionalPreprocessorIfPPCallbacks>(*this, 10252296f5eSPiotr Zegar *PP)); 10352296f5eSPiotr Zegar } 10452296f5eSPiotr Zegar 10552296f5eSPiotr Zegar } // namespace clang::tidy::readability 106