ReplaceDisallowCopyAndAssignMacroCheck.cpp 3.3 KB

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