10 #include "clang/Frontend/CompilerInstance.h" 11 #include "clang/Lex/MacroArgs.h" 12 #include "clang/Lex/PPCallbacks.h" 13 #include "clang/Lex/Preprocessor.h" 20 class MacroRepeatedPPCallbacks :
public PPCallbacks {
22 MacroRepeatedPPCallbacks(ClangTidyCheck &Check, Preprocessor &PP)
23 : Check(Check), PP(PP) {}
25 void MacroExpands(
const Token &MacroNameTok,
const MacroDefinition &
MD,
26 SourceRange
Range,
const MacroArgs *Args)
override;
29 ClangTidyCheck &Check;
32 unsigned countArgumentExpansions(
const MacroInfo *MI,
33 const IdentifierInfo *Arg)
const;
35 bool hasSideEffects(
const Token *ResultArgToks)
const;
39 void MacroRepeatedPPCallbacks::MacroExpands(
const Token &MacroNameTok,
40 const MacroDefinition &
MD,
42 const MacroArgs *Args) {
44 if (!Range.getBegin().isFileID())
47 const MacroInfo *MI = MD.getMacroInfo();
52 MI->tokens().begin(), MI->tokens().end(), [](
const Token &T) {
53 return T.isOneOf(tok::kw_if, tok::kw_else, tok::kw_switch,
54 tok::kw_case, tok::kw_break, tok::kw_while,
55 tok::kw_do, tok::kw_for, tok::kw_continue,
56 tok::kw_goto, tok::kw_return);
57 }) != MI->tokens().end())
60 for (
unsigned ArgNo = 0U; ArgNo < MI->getNumParams(); ++ArgNo) {
61 const IdentifierInfo *Arg = *(MI->param_begin() + ArgNo);
62 const Token *ResultArgToks = Args->getUnexpArgument(ArgNo);
64 if (hasSideEffects(ResultArgToks) &&
65 countArgumentExpansions(MI, Arg) >= 2) {
66 Check.diag(ResultArgToks->getLocation(),
67 "side effects in the %ordinal0 macro argument %1 are " 68 "repeated in macro expansion")
69 << (ArgNo + 1) << Arg;
70 Check.diag(MI->getDefinitionLoc(),
"macro %0 defined here",
72 << MacroNameTok.getIdentifierInfo();
77 unsigned MacroRepeatedPPCallbacks::countArgumentExpansions(
78 const MacroInfo *MI,
const IdentifierInfo *Arg)
const {
84 bool SkipParen =
false;
85 int SkipParenCount = 0;
87 bool FoundBuiltin =
false;
88 bool PrevTokenIsHash =
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::hash)) {
103 PrevTokenIsHash =
true;
106 if (PrevTokenIsHash) {
107 PrevTokenIsHash =
false;
112 if (T.is(tok::question)) {
113 CountAtQuestion.push(Current);
114 }
else if (T.is(tok::colon)) {
115 if (CountAtQuestion.empty())
117 Current = CountAtQuestion.top();
118 CountAtQuestion.pop();
123 if (T.is(tok::l_paren))
125 else if (T.is(tok::r_paren))
127 SkipParen = (SkipParenCount != 0);
132 IdentifierInfo *TII = T.getIdentifierInfo();
140 if (TII->getBuiltinID() == Builtin::BI__builtin_constant_p) {
148 if (TII->hasMacroDefinition()) {
149 const MacroInfo *M = PP.getMacroDefinition(TII).getMacroInfo();
150 if (M !=
nullptr && M->isFunctionLike())
165 bool MacroRepeatedPPCallbacks::hasSideEffects(
166 const Token *ResultArgToks)
const {
167 for (; ResultArgToks->isNot(tok::eof); ++ResultArgToks) {
168 if (ResultArgToks->isOneOf(tok::plusplus, tok::minusminus))
175 const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) {
176 PP->addPPCallbacks(::llvm::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.