1e636e6b7SKonrad Kleine //===--- ReplaceDisallowCopyAndAssignMacroCheck.cpp - clang-tidy ----------===//
2e636e6b7SKonrad Kleine //
3e636e6b7SKonrad Kleine // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e636e6b7SKonrad Kleine // See https://llvm.org/LICENSE.txt for license information.
5e636e6b7SKonrad Kleine // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e636e6b7SKonrad Kleine //
7e636e6b7SKonrad Kleine //===----------------------------------------------------------------------===//
8e636e6b7SKonrad Kleine
9e636e6b7SKonrad Kleine #include "ReplaceDisallowCopyAndAssignMacroCheck.h"
10e636e6b7SKonrad Kleine #include "clang/Frontend/CompilerInstance.h"
11e636e6b7SKonrad Kleine #include "clang/Lex/MacroArgs.h"
12860aefd0SNathan James #include "clang/Lex/PPCallbacks.h"
13860aefd0SNathan James #include "clang/Lex/Preprocessor.h"
14e636e6b7SKonrad Kleine #include "llvm/Support/FormatVariadic.h"
1571f55735SKazu Hirata #include <optional>
16e636e6b7SKonrad Kleine
17*7d2ea6c4SCarlos Galvez namespace clang::tidy::modernize {
18e636e6b7SKonrad Kleine
19e636e6b7SKonrad Kleine namespace {
20e636e6b7SKonrad Kleine
21e636e6b7SKonrad Kleine class ReplaceDisallowCopyAndAssignMacroCallbacks : public PPCallbacks {
22e636e6b7SKonrad Kleine public:
ReplaceDisallowCopyAndAssignMacroCallbacks(ReplaceDisallowCopyAndAssignMacroCheck & Check,Preprocessor & PP)23e636e6b7SKonrad Kleine explicit ReplaceDisallowCopyAndAssignMacroCallbacks(
24e636e6b7SKonrad Kleine ReplaceDisallowCopyAndAssignMacroCheck &Check, Preprocessor &PP)
25e636e6b7SKonrad Kleine : Check(Check), PP(PP) {}
26e636e6b7SKonrad Kleine
MacroExpands(const Token & MacroNameTok,const MacroDefinition & MD,SourceRange Range,const MacroArgs * Args)27e636e6b7SKonrad Kleine void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD,
28e636e6b7SKonrad Kleine SourceRange Range, const MacroArgs *Args) override {
29e636e6b7SKonrad Kleine IdentifierInfo *Info = MacroNameTok.getIdentifierInfo();
30e636e6b7SKonrad Kleine if (!Info || !Args || Args->getNumMacroArguments() != 1)
31e636e6b7SKonrad Kleine return;
32e636e6b7SKonrad Kleine if (Info->getName() != Check.getMacroName())
33e636e6b7SKonrad Kleine return;
34ade0662cSSalman Javed // The first argument to the DISALLOW_COPY_AND_ASSIGN macro is expected to
35e636e6b7SKonrad Kleine // be the class name.
36e636e6b7SKonrad Kleine const Token *ClassNameTok = Args->getUnexpArgument(0);
37e636e6b7SKonrad Kleine if (Args->ArgNeedsPreexpansion(ClassNameTok, PP))
38e636e6b7SKonrad Kleine // For now we only support simple argument that don't need to be
39e636e6b7SKonrad Kleine // pre-expanded.
40e636e6b7SKonrad Kleine return;
41e636e6b7SKonrad Kleine clang::IdentifierInfo *ClassIdent = ClassNameTok->getIdentifierInfo();
42e636e6b7SKonrad Kleine if (!ClassIdent)
43e636e6b7SKonrad Kleine return;
44e636e6b7SKonrad Kleine
45e636e6b7SKonrad Kleine std::string Replacement = llvm::formatv(
46e636e6b7SKonrad Kleine R"cpp({0}(const {0} &) = delete;
47e636e6b7SKonrad Kleine const {0} &operator=(const {0} &) = delete{1})cpp",
48e636e6b7SKonrad Kleine ClassIdent->getName(), shouldAppendSemi(Range) ? ";" : "");
49e636e6b7SKonrad Kleine
50e636e6b7SKonrad Kleine Check.diag(MacroNameTok.getLocation(),
51e636e6b7SKonrad Kleine "prefer deleting copy constructor and assignment operator over "
52e636e6b7SKonrad Kleine "using macro '%0'")
53e636e6b7SKonrad Kleine << Check.getMacroName()
54e636e6b7SKonrad Kleine << FixItHint::CreateReplacement(
55e636e6b7SKonrad Kleine PP.getSourceManager().getExpansionRange(Range), Replacement);
56e636e6b7SKonrad Kleine }
57e636e6b7SKonrad Kleine
58e636e6b7SKonrad Kleine private:
59e636e6b7SKonrad Kleine /// \returns \c true if the next token after the given \p MacroLoc is \b not a
60e636e6b7SKonrad Kleine /// semicolon.
shouldAppendSemi(SourceRange MacroLoc)61e636e6b7SKonrad Kleine bool shouldAppendSemi(SourceRange MacroLoc) {
62f71ffd3bSKazu Hirata std::optional<Token> Next = Lexer::findNextToken(
63e636e6b7SKonrad Kleine MacroLoc.getEnd(), PP.getSourceManager(), PP.getLangOpts());
64e636e6b7SKonrad Kleine return !(Next && Next->is(tok::semi));
65e636e6b7SKonrad Kleine }
66e636e6b7SKonrad Kleine
67e636e6b7SKonrad Kleine ReplaceDisallowCopyAndAssignMacroCheck &Check;
68e636e6b7SKonrad Kleine Preprocessor &PP;
69e636e6b7SKonrad Kleine };
70e636e6b7SKonrad Kleine } // namespace
71e636e6b7SKonrad Kleine
ReplaceDisallowCopyAndAssignMacroCheck(StringRef Name,ClangTidyContext * Context)72e636e6b7SKonrad Kleine ReplaceDisallowCopyAndAssignMacroCheck::ReplaceDisallowCopyAndAssignMacroCheck(
73e636e6b7SKonrad Kleine StringRef Name, ClangTidyContext *Context)
74e636e6b7SKonrad Kleine : ClangTidyCheck(Name, Context),
75e636e6b7SKonrad Kleine MacroName(Options.get("MacroName", "DISALLOW_COPY_AND_ASSIGN")) {}
76e636e6b7SKonrad Kleine
registerPPCallbacks(const SourceManager & SM,Preprocessor * PP,Preprocessor * ModuleExpanderPP)77e636e6b7SKonrad Kleine void ReplaceDisallowCopyAndAssignMacroCheck::registerPPCallbacks(
78e636e6b7SKonrad Kleine const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) {
79e636e6b7SKonrad Kleine PP->addPPCallbacks(
80e636e6b7SKonrad Kleine ::std::make_unique<ReplaceDisallowCopyAndAssignMacroCallbacks>(
81e636e6b7SKonrad Kleine *this, *ModuleExpanderPP));
82e636e6b7SKonrad Kleine }
83e636e6b7SKonrad Kleine
storeOptions(ClangTidyOptions::OptionMap & Opts)84e636e6b7SKonrad Kleine void ReplaceDisallowCopyAndAssignMacroCheck::storeOptions(
85e636e6b7SKonrad Kleine ClangTidyOptions::OptionMap &Opts) {
86e636e6b7SKonrad Kleine Options.store(Opts, "MacroName", MacroName);
87e636e6b7SKonrad Kleine }
88e636e6b7SKonrad Kleine
89*7d2ea6c4SCarlos Galvez } // namespace clang::tidy::modernize
90