105 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "AvoidUnconditionalPreprocessorIfCheck.h"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 16namespace clang::tidy::readability {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 else36 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} // namespace96 97void AvoidUnconditionalPreprocessorIfCheck::registerPPCallbacks(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::readability105