11 #include "clang/Frontend/CompilerInstance.h"
12 #include "clang/Lex/PPCallbacks.h"
13 #include "clang/Lex/Preprocessor.h"
14 #include "clang/Lex/MacroArgs.h"
21 class MacroRepeatedPPCallbacks :
public PPCallbacks {
23 MacroRepeatedPPCallbacks(ClangTidyCheck &
Check, Preprocessor &
PP)
24 : Check(Check), PP(PP) {}
26 void MacroExpands(
const Token &MacroNameTok,
const MacroDefinition &MD,
27 SourceRange
Range,
const MacroArgs *Args)
override;
33 unsigned countArgumentExpansions(
const MacroInfo *MI,
34 const IdentifierInfo *Arg)
const;
36 bool hasSideEffects(
const Token *ResultArgToks)
const;
40 void MacroRepeatedPPCallbacks::MacroExpands(
const Token &MacroNameTok,
41 const MacroDefinition &MD,
43 const MacroArgs *Args) {
45 if (!Range.getBegin().isFileID())
48 const MacroInfo *MI = MD.getMacroInfo();
53 MI->tokens().begin(), MI->tokens().end(), [](
const Token &T) {
54 return T.isOneOf(tok::kw_if, tok::kw_else, tok::kw_switch,
55 tok::kw_case, tok::kw_break, tok::kw_while,
56 tok::kw_do, tok::kw_for, tok::kw_continue,
57 tok::kw_goto, tok::kw_return);
58 }) != MI->tokens().end())
61 for (
unsigned ArgNo = 0U; ArgNo < MI->getNumArgs(); ++ArgNo) {
62 const IdentifierInfo *Arg = *(MI->arg_begin() + ArgNo);
63 const Token *ResultArgToks = Args->getUnexpArgument(ArgNo);
65 if (hasSideEffects(ResultArgToks) &&
66 countArgumentExpansions(MI, Arg) >= 2) {
67 Check.diag(ResultArgToks->getLocation(),
68 "side effects in the %ordinal0 macro argument '%1' are "
69 "repeated in macro expansion")
70 << (ArgNo + 1) << Arg->getName();
71 Check.diag(MI->getDefinitionLoc(),
"macro %0 defined here",
73 << MacroNameTok.getIdentifierInfo();
78 unsigned MacroRepeatedPPCallbacks::countArgumentExpansions(
79 const MacroInfo *MI,
const IdentifierInfo *Arg)
const {
85 bool SkipParen =
false;
86 int SkipParenCount = 0;
88 bool FoundBuiltin =
false;
91 std::stack<unsigned, SmallVector<unsigned, 8>> CountAtQuestion;
92 for (
const auto &T : MI->tokens()) {
98 if (FoundBuiltin && T.isOneOf(tok::question, tok::ampamp, tok::pipepipe))
102 if (T.is(tok::question)) {
103 CountAtQuestion.push(Current);
104 }
else if (T.is(tok::colon)) {
105 if (CountAtQuestion.empty())
107 Current = CountAtQuestion.top();
108 CountAtQuestion.pop();
113 if (T.is(tok::l_paren))
115 else if (T.is(tok::r_paren))
117 SkipParen = (SkipParenCount != 0);
122 IdentifierInfo *TII = T.getIdentifierInfo();
130 if (TII->getBuiltinID() == Builtin::BI__builtin_constant_p) {
138 if (TII->hasMacroDefinition()) {
139 const MacroInfo *M =
PP.getMacroDefinition(TII).getMacroInfo();
140 if (M !=
nullptr && M->isFunctionLike())
155 bool MacroRepeatedPPCallbacks::hasSideEffects(
156 const Token *ResultArgToks)
const {
157 for (; ResultArgToks->isNot(tok::eof); ++ResultArgToks) {
158 if (ResultArgToks->isOneOf(tok::plusplus, tok::minusminus))
165 CompilerInstance &Compiler) {
166 Compiler.getPreprocessor().addPPCallbacks(
167 ::llvm::make_unique<MacroRepeatedPPCallbacks>(
168 *
this, Compiler.getPreprocessor()));
void registerPPCallbacks(CompilerInstance &Compiler) override
Override this to register PPCallbacks with Compiler.
CharSourceRange Range
SourceRange for the file name.