brintos

brintos / llvm-project-archived public Read only

0
0
Text · 3.3 KiB · be5e21d Raw
90 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 "ReplaceDisallowCopyAndAssignMacroCheck.h"10#include "clang/Frontend/CompilerInstance.h"11#include "clang/Lex/MacroArgs.h"12#include "clang/Lex/PPCallbacks.h"13#include "clang/Lex/Preprocessor.h"14#include "llvm/Support/FormatVariadic.h"15#include <optional>16 17namespace clang::tidy::modernize {18 19namespace {20 21class ReplaceDisallowCopyAndAssignMacroCallbacks : public PPCallbacks {22public:23  explicit ReplaceDisallowCopyAndAssignMacroCallbacks(24      ReplaceDisallowCopyAndAssignMacroCheck &Check, Preprocessor &PP)25      : Check(Check), PP(PP) {}26 27  void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD,28                    SourceRange Range, const MacroArgs *Args) override {29    const IdentifierInfo *Info = MacroNameTok.getIdentifierInfo();30    if (!Info || !Args || Args->getNumMacroArguments() != 1)31      return;32    if (Info->getName() != Check.getMacroName())33      return;34    // The first argument to the DISALLOW_COPY_AND_ASSIGN macro is expected to35    // be the class name.36    const Token *ClassNameTok = Args->getUnexpArgument(0);37    if (Args->ArgNeedsPreexpansion(ClassNameTok, PP))38      // For now we only support simple argument that don't need to be39      // pre-expanded.40      return;41    const clang::IdentifierInfo *ClassIdent = ClassNameTok->getIdentifierInfo();42    if (!ClassIdent)43      return;44 45    const std::string Replacement = llvm::formatv(46        R"cpp({0}(const {0} &) = delete;47const {0} &operator=(const {0} &) = delete{1})cpp",48        ClassIdent->getName(), shouldAppendSemi(Range) ? ";" : "");49 50    Check.diag(MacroNameTok.getLocation(),51               "prefer deleting copy constructor and assignment operator over "52               "using macro '%0'")53        << Check.getMacroName()54        << FixItHint::CreateReplacement(55               PP.getSourceManager().getExpansionRange(Range), Replacement);56  }57 58private:59  /// \returns \c true if the next token after the given \p MacroLoc is \b not a60  /// semicolon.61  bool shouldAppendSemi(SourceRange MacroLoc) {62    std::optional<Token> Next = Lexer::findNextToken(63        MacroLoc.getEnd(), PP.getSourceManager(), PP.getLangOpts());64    return !(Next && Next->is(tok::semi));65  }66 67  ReplaceDisallowCopyAndAssignMacroCheck &Check;68  Preprocessor &PP;69};70} // namespace71 72ReplaceDisallowCopyAndAssignMacroCheck::ReplaceDisallowCopyAndAssignMacroCheck(73    StringRef Name, ClangTidyContext *Context)74    : ClangTidyCheck(Name, Context),75      MacroName(Options.get("MacroName", "DISALLOW_COPY_AND_ASSIGN")) {}76 77void ReplaceDisallowCopyAndAssignMacroCheck::registerPPCallbacks(78    const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) {79  PP->addPPCallbacks(80      ::std::make_unique<ReplaceDisallowCopyAndAssignMacroCallbacks>(81          *this, *ModuleExpanderPP));82}83 84void ReplaceDisallowCopyAndAssignMacroCheck::storeOptions(85    ClangTidyOptions::OptionMap &Opts) {86  Options.store(Opts, "MacroName", MacroName);87}88 89} // namespace clang::tidy::modernize90