brintos

brintos / llvm-project-archived public Read only

0
0
Text · 4.3 KiB · b301a2b Raw
120 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 "MacroUsageCheck.h"10#include "clang/Basic/TokenKinds.h"11#include "clang/Frontend/CompilerInstance.h"12#include "clang/Lex/PPCallbacks.h"13#include "clang/Lex/Preprocessor.h"14#include "llvm/ADT/STLExtras.h"15#include "llvm/Support/Regex.h"16#include <cctype>17#include <functional>18 19namespace clang::tidy::cppcoreguidelines {20 21static bool isCapsOnly(StringRef Name) {22  return llvm::all_of(Name, [](const char C) {23    return std::isupper(C) || std::isdigit(C) || C == '_';24  });25}26 27namespace {28 29class MacroUsageCallbacks : public PPCallbacks {30public:31  MacroUsageCallbacks(MacroUsageCheck *Check, const SourceManager &SM,32                      StringRef RegExpStr, bool CapsOnly,33                      bool IgnoreCommandLine)34      : Check(Check), SM(SM), RegExp(RegExpStr), CheckCapsOnly(CapsOnly),35        IgnoreCommandLineMacros(IgnoreCommandLine) {}36  void MacroDefined(const Token &MacroNameTok,37                    const MacroDirective *MD) override {38    if (SM.isWrittenInBuiltinFile(MD->getLocation()) ||39        MD->getMacroInfo()->isUsedForHeaderGuard() ||40        MD->getMacroInfo()->tokens_empty() ||41        llvm::any_of(MD->getMacroInfo()->tokens(), [](const Token &T) {42          return T.isOneOf(tok::TokenKind::hash, tok::TokenKind::hashhash);43        }))44      return;45 46    if (IgnoreCommandLineMacros &&47        SM.isWrittenInCommandLineFile(MD->getLocation()))48      return;49 50    const StringRef MacroName = MacroNameTok.getIdentifierInfo()->getName();51    if (MacroName == "__GCC_HAVE_DWARF2_CFI_ASM")52      return;53    if (!CheckCapsOnly && !RegExp.match(MacroName))54      Check->warnMacro(MD, MacroName);55 56    if (CheckCapsOnly && !isCapsOnly(MacroName))57      Check->warnNaming(MD, MacroName);58  }59 60private:61  MacroUsageCheck *Check;62  const SourceManager &SM;63  const llvm::Regex RegExp;64  bool CheckCapsOnly;65  bool IgnoreCommandLineMacros;66};67} // namespace68 69void MacroUsageCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {70  Options.store(Opts, "AllowedRegexp", AllowedRegexp);71  Options.store(Opts, "CheckCapsOnly", CheckCapsOnly);72  Options.store(Opts, "IgnoreCommandLineMacros", IgnoreCommandLineMacros);73}74 75void MacroUsageCheck::registerPPCallbacks(const SourceManager &SM,76                                          Preprocessor *PP,77                                          Preprocessor *ModuleExpanderPP) {78  PP->addPPCallbacks(std::make_unique<MacroUsageCallbacks>(79      this, SM, AllowedRegexp, CheckCapsOnly, IgnoreCommandLineMacros));80}81 82void MacroUsageCheck::warnMacro(const MacroDirective *MD, StringRef MacroName) {83  const MacroInfo *Info = MD->getMacroInfo();84  StringRef Message;85  bool MacroBodyExpressionLike;86  if (Info->getNumTokens() > 0) {87    const Token &Tok = Info->getReplacementToken(0);88    // Now notice that keywords like `__attribute` cannot be a leading89    // token in an expression.90    MacroBodyExpressionLike = !Tok.is(tok::kw___attribute);91  } else {92    MacroBodyExpressionLike = true;93  }94 95  if (llvm::all_of(Info->tokens(), std::mem_fn(&Token::isLiteral)))96    Message = "macro '%0' used to declare a constant; consider using a "97              "'constexpr' constant";98  // A variadic macro is function-like at the same time. Therefore variadic99  // macros are checked first and will be excluded for the function-like100  // diagnostic.101  else if (Info->isVariadic() && MacroBodyExpressionLike)102    Message = "variadic macro '%0' used; consider using a 'constexpr' "103              "variadic template function";104  else if (Info->isFunctionLike() && MacroBodyExpressionLike)105    Message = "function-like macro '%0' used; consider a 'constexpr' template "106              "function";107 108  if (!Message.empty())109    diag(MD->getLocation(), Message) << MacroName;110}111 112void MacroUsageCheck::warnNaming(const MacroDirective *MD,113                                 StringRef MacroName) {114  diag(MD->getLocation(), "macro definition does not define the macro name "115                          "'%0' using all uppercase characters")116      << MacroName;117}118 119} // namespace clang::tidy::cppcoreguidelines120