1 //===--- ReplaceDisallowCopyAndAssignMacroCheck.cpp - clang-tidy ----------===//
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
7 //===----------------------------------------------------------------------===//
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"
17 namespace clang::tidy::modernize
{
21 class ReplaceDisallowCopyAndAssignMacroCallbacks
: public PPCallbacks
{
23 explicit ReplaceDisallowCopyAndAssignMacroCallbacks(
24 ReplaceDisallowCopyAndAssignMacroCheck
&Check
, Preprocessor
&PP
)
25 : Check(Check
), PP(PP
) {}
27 void MacroExpands(const Token
&MacroNameTok
, const MacroDefinition
&MD
,
28 SourceRange Range
, const MacroArgs
*Args
) override
{
29 IdentifierInfo
*Info
= MacroNameTok
.getIdentifierInfo();
30 if (!Info
|| !Args
|| Args
->getNumMacroArguments() != 1)
32 if (Info
->getName() != Check
.getMacroName())
34 // The first argument to the DISALLOW_COPY_AND_ASSIGN macro is expected to
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 be
41 clang::IdentifierInfo
*ClassIdent
= ClassNameTok
->getIdentifierInfo();
45 std::string Replacement
= llvm::formatv(
46 R
"cpp({0}(const {0} &) = delete;
47 const {0} &operator=(const {0} &) = delete{1})cpp",
48 ClassIdent
->getName(), shouldAppendSemi(Range
) ? ";" : "");
50 Check
.diag(MacroNameTok
.getLocation(),
51 "prefer deleting copy constructor and assignment operator over "
53 << Check
.getMacroName()
54 << FixItHint::CreateReplacement(
55 PP
.getSourceManager().getExpansionRange(Range
), Replacement
);
59 /// \returns \c true if the next token after the given \p MacroLoc is \b not a
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
));
67 ReplaceDisallowCopyAndAssignMacroCheck
&Check
;
72 ReplaceDisallowCopyAndAssignMacroCheck::ReplaceDisallowCopyAndAssignMacroCheck(
73 StringRef Name
, ClangTidyContext
*Context
)
74 : ClangTidyCheck(Name
, Context
),
75 MacroName(Options
.get("MacroName", "DISALLOW_COPY_AND_ASSIGN")) {}
77 void ReplaceDisallowCopyAndAssignMacroCheck::registerPPCallbacks(
78 const SourceManager
&SM
, Preprocessor
*PP
, Preprocessor
*ModuleExpanderPP
) {
80 ::std::make_unique
<ReplaceDisallowCopyAndAssignMacroCallbacks
>(
81 *this, *ModuleExpanderPP
));
84 void ReplaceDisallowCopyAndAssignMacroCheck::storeOptions(
85 ClangTidyOptions::OptionMap
&Opts
) {
86 Options
.store(Opts
, "MacroName", MacroName
);
89 } // namespace clang::tidy::modernize