10 #include "clang/Basic/Builtins.h" 11 #include "clang/Frontend/CompilerInstance.h" 12 #include "clang/Lex/MacroArgs.h" 13 #include "clang/Lex/PPCallbacks.h" 14 #include "clang/Lex/Preprocessor.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;
30 ClangTidyCheck &Check;
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->getNumParams(); ++ArgNo) {
62 const IdentifierInfo *Arg = *(MI->param_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;
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;
89 bool PrevTokenIsHash =
false;
92 std::stack<unsigned, SmallVector<unsigned, 8>> CountAtQuestion;
93 for (
const auto &T : MI->tokens()) {
99 if (FoundBuiltin && T.isOneOf(tok::question, tok::ampamp, tok::pipepipe))
103 if (T.is(tok::hash)) {
104 PrevTokenIsHash =
true;
107 if (PrevTokenIsHash) {
108 PrevTokenIsHash =
false;
113 if (T.is(tok::question)) {
114 CountAtQuestion.push(Current);
115 }
else if (T.is(tok::colon)) {
116 if (CountAtQuestion.empty())
118 Current = CountAtQuestion.top();
119 CountAtQuestion.pop();
124 if (T.is(tok::l_paren))
126 else if (T.is(tok::r_paren))
128 SkipParen = (SkipParenCount != 0);
133 IdentifierInfo *TII = T.getIdentifierInfo();
141 if (TII->getBuiltinID() == Builtin::BI__builtin_constant_p) {
149 if (TII->hasMacroDefinition()) {
150 const MacroInfo *M =
PP.getMacroDefinition(TII).getMacroInfo();
151 if (M !=
nullptr && M->isFunctionLike())
166 bool MacroRepeatedPPCallbacks::hasSideEffects(
167 const Token *ResultArgToks)
const {
168 for (; ResultArgToks->isNot(tok::eof); ++ResultArgToks) {
169 if (ResultArgToks->isOneOf(tok::plusplus, tok::minusminus))
176 const SourceManager &SM, Preprocessor *
PP, Preprocessor *ModuleExpanderPP) {
177 PP->addPPCallbacks(::std::make_unique<MacroRepeatedPPCallbacks>(*
this, *PP));
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
static GeneratorRegistry::Add< MDGenerator > MD(MDGenerator::Format, "Generator for MD output.")
CharSourceRange Range
SourceRange for the file name.
void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) override
Override this to register PPCallbacks in the preprocessor.