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"
22 class ReplaceDisallowCopyAndAssignMacroCallbacks
: public PPCallbacks
{
24 explicit ReplaceDisallowCopyAndAssignMacroCallbacks(
25 ReplaceDisallowCopyAndAssignMacroCheck
&Check
, Preprocessor
&PP
)
26 : Check(Check
), PP(PP
) {}
28 void MacroExpands(const Token
&MacroNameTok
, const MacroDefinition
&MD
,
29 SourceRange Range
, const MacroArgs
*Args
) override
{
30 IdentifierInfo
*Info
= MacroNameTok
.getIdentifierInfo();
31 if (!Info
|| !Args
|| Args
->getNumMacroArguments() != 1)
33 if (Info
->getName() != Check
.getMacroName())
35 // The first argument to the DISALLOW_COPY_AND_ASSIGN macro is expected to
37 const Token
*ClassNameTok
= Args
->getUnexpArgument(0);
38 if (Args
->ArgNeedsPreexpansion(ClassNameTok
, PP
))
39 // For now we only support simple argument that don't need to be
42 clang::IdentifierInfo
*ClassIdent
= ClassNameTok
->getIdentifierInfo();
46 std::string Replacement
= llvm::formatv(
47 R
"cpp({0}(const {0} &) = delete;
48 const {0} &operator=(const {0} &) = delete{1})cpp",
49 ClassIdent
->getName(), shouldAppendSemi(Range
) ? ";" : "");
51 Check
.diag(MacroNameTok
.getLocation(),
52 "prefer deleting copy constructor and assignment operator over "
54 << Check
.getMacroName()
55 << FixItHint::CreateReplacement(
56 PP
.getSourceManager().getExpansionRange(Range
), Replacement
);
60 /// \returns \c true if the next token after the given \p MacroLoc is \b not a
62 bool shouldAppendSemi(SourceRange MacroLoc
) {
63 llvm::Optional
<Token
> Next
= Lexer::findNextToken(
64 MacroLoc
.getEnd(), PP
.getSourceManager(), PP
.getLangOpts());
65 return !(Next
&& Next
->is(tok::semi
));
68 ReplaceDisallowCopyAndAssignMacroCheck
&Check
;
73 ReplaceDisallowCopyAndAssignMacroCheck::ReplaceDisallowCopyAndAssignMacroCheck(
74 StringRef Name
, ClangTidyContext
*Context
)
75 : ClangTidyCheck(Name
, Context
),
76 MacroName(Options
.get("MacroName", "DISALLOW_COPY_AND_ASSIGN")) {}
78 void ReplaceDisallowCopyAndAssignMacroCheck::registerPPCallbacks(
79 const SourceManager
&SM
, Preprocessor
*PP
, Preprocessor
*ModuleExpanderPP
) {
81 ::std::make_unique
<ReplaceDisallowCopyAndAssignMacroCallbacks
>(
82 *this, *ModuleExpanderPP
));
85 void ReplaceDisallowCopyAndAssignMacroCheck::storeOptions(
86 ClangTidyOptions::OptionMap
&Opts
) {
87 Options
.store(Opts
, "MacroName", MacroName
);
90 } // namespace modernize