10 #include "clang/Frontend/CompilerInstance.h"
11 #include "clang/Lex/PPCallbacks.h"
12 #include "clang/Lex/Preprocessor.h"
19 class MacroParenthesesPPCallbacks :
public PPCallbacks {
21 MacroParenthesesPPCallbacks(Preprocessor *
PP, MacroParenthesesCheck *Check)
22 :
PP(
PP), Check(Check) {}
24 void MacroDefined(
const Token &MacroNameTok,
25 const MacroDirective *
MD)
override {
26 replacementList(MacroNameTok,
MD->getMacroInfo());
27 argument(MacroNameTok,
MD->getMacroInfo());
32 void replacementList(
const Token &MacroNameTok,
const MacroInfo *MI);
35 void argument(
const Token &MacroNameTok,
const MacroInfo *MI);
38 MacroParenthesesCheck *Check;
44 return T.isOneOf(tok::l_paren, tok::l_brace, tok::l_square, tok::comma,
50 return T.isOneOf(tok::r_paren, tok::r_brace, tok::r_square, tok::comma,
57 return T.isOneOf(tok::kw_if, tok::kw_case, tok::kw_const, tok::kw_struct);
64 return T.isOneOf(tok::plus, tok::minus, tok::star, tok::slash, tok::percent,
65 tok::amp, tok::pipe, tok::caret);
70 return T.isOneOf(tok::kw_bool, tok::kw_char, tok::kw_short, tok::kw_int,
71 tok::kw_long, tok::kw_float, tok::kw_double, tok::kw_const,
72 tok::kw_enum, tok::kw_inline, tok::kw_static, tok::kw_struct,
73 tok::kw_signed, tok::kw_unsigned);
78 if (Tok == MI->tokens_end())
87 if (!Tok->isOneOf(tok::identifier, tok::raw_identifier, tok::coloncolon))
91 while (Tok != MI->tokens_end() &&
92 Tok->isOneOf(tok::identifier, tok::raw_identifier, tok::coloncolon,
93 tok::star, tok::amp, tok::ampamp, tok::less,
98 return Tok == MI->tokens_end() ||
99 Tok->isOneOf(tok::equal, tok::semi, tok::l_square, tok::l_paren) ||
103 void MacroParenthesesPPCallbacks::replacementList(
const Token &MacroNameTok,
104 const MacroInfo *MI) {
115 for (
auto TI = MI->tokens_begin(), TE = MI->tokens_end(); TI != TE; ++TI) {
116 const Token &Tok = *TI;
121 if (Count == 0 && Tok.isOneOf(tok::comma, tok::semi))
123 if (Tok.isOneOf(tok::l_paren, tok::l_brace, tok::l_square)) {
125 }
else if (Tok.isOneOf(tok::r_paren, tok::r_brace, tok::r_square)) {
130 }
else if (Count == 0 &&
isWarnOp(Tok)) {
134 if (TI == MI->tokens_begin() && (TI + 1) != TE &&
135 !Tok.isOneOf(tok::plus, tok::minus))
139 if ((TE - 1)->is(tok::star))
142 Loc = Tok.getLocation();
146 const Token &Last = *(MI->tokens_end() - 1);
147 Check->
diag(
Loc,
"macro replacement list should be enclosed in parentheses")
148 << FixItHint::CreateInsertion(MI->tokens_begin()->getLocation(),
"(")
149 << FixItHint::CreateInsertion(Last.getLocation().getLocWithOffset(
150 PP->getSpelling(Last).length()),
155 void MacroParenthesesPPCallbacks::argument(
const Token &MacroNameTok,
156 const MacroInfo *MI) {
161 for (
auto TI = MI->tokens_begin(), TE = MI->tokens_end(); TI != TE; ++TI) {
163 if (TI == MI->tokens_begin())
167 if ((TI + 1) == MI->tokens_end())
170 const Token &Prev = *(TI - 1);
171 const Token &Next = *(TI + 1);
173 const Token &Tok = *TI;
177 if (Tok.isOneOf(tok::equal, tok::semi, tok::l_square, tok::l_paren))
183 if (!Tok.isOneOf(tok::identifier, tok::raw_identifier))
187 if (MI->getParameterNum(Tok.getIdentifierInfo()) < 0)
195 if (Prev.isOneOf(tok::hash, tok::hashhash) || Next.is(tok::hashhash))
199 if (Prev.isOneOf(tok::period, tok::arrow, tok::coloncolon, tok::arrowstar,
204 if (Next.is(tok::coloncolon))
208 if (isStringLiteral(Prev.getKind()) || isStringLiteral(Next.getKind()))
212 if (isAnyIdentifier(Prev.getKind()) ||
isKeyword(Prev) ||
213 isAnyIdentifier(Next.getKind()) ||
isKeyword(Next))
217 if (Next.is(tok::l_paren))
221 if (Prev.is(tok::l_paren) && Next.is(tok::star) &&
222 TI + 2 != MI->tokens_end() && (TI + 2)->is(tok::r_paren))
226 if (Prev.isOneOf(tok::equal, tok::kw_return) && Next.is(tok::semi))
230 if (
PP->getLangOpts().CPlusPlus && Prev.isOneOf(tok::comma, tok::less) &&
231 Next.isOneOf(tok::comma, tok::greater))
235 if (Prev.is(tok::kw_namespace))
239 if (MI->isVariadic())
242 Check->
diag(Tok.getLocation(),
"macro argument should be enclosed in "
244 << FixItHint::CreateInsertion(Tok.getLocation(),
"(")
245 << FixItHint::CreateInsertion(Tok.getLocation().getLocWithOffset(
246 PP->getSpelling(Tok).length()),
252 const SourceManager &SM, Preprocessor *
PP, Preprocessor *ModuleExpanderPP) {
253 PP->addPPCallbacks(std::make_unique<MacroParenthesesPPCallbacks>(
PP,
this));