10#include "clang/Frontend/CompilerInstance.h"
11#include "clang/Lex/PPCallbacks.h"
12#include "clang/Lex/Preprocessor.h"
17class MacroParenthesesPPCallbacks :
public PPCallbacks {
19 MacroParenthesesPPCallbacks(Preprocessor *PP, MacroParenthesesCheck *Check)
20 : PP(PP), Check(Check) {}
22 void MacroDefined(
const Token &MacroNameTok,
23 const MacroDirective *MD)
override {
24 replacementList(MacroNameTok, MD->getMacroInfo());
25 argument(MacroNameTok, MD->getMacroInfo());
30 void replacementList(
const Token &MacroNameTok,
const MacroInfo *MI);
33 void argument(
const Token &MacroNameTok,
const MacroInfo *MI);
36 MacroParenthesesCheck *Check;
42 return T.isOneOf(tok::l_paren, tok::l_brace, tok::l_square, tok::comma,
48 return T.isOneOf(tok::r_paren, tok::r_brace, tok::r_square, tok::comma,
55 return T.isOneOf(tok::kw_if, tok::kw_case, tok::kw_const, tok::kw_struct);
62 return T.isOneOf(tok::plus, tok::minus, tok::star, tok::slash, tok::percent,
63 tok::amp, tok::pipe, tok::caret);
68 return T.isOneOf(tok::kw_bool, tok::kw_char, tok::kw_short, tok::kw_int,
69 tok::kw_long, tok::kw_float, tok::kw_double, tok::kw_const,
70 tok::kw_enum, tok::kw_inline, tok::kw_static, tok::kw_struct,
71 tok::kw_signed, tok::kw_unsigned);
76 if (Tok == MI->tokens_end())
85 if (!Tok->isOneOf(tok::identifier, tok::raw_identifier, tok::coloncolon))
89 while (Tok != MI->tokens_end() &&
90 Tok->isOneOf(tok::identifier, tok::raw_identifier, tok::coloncolon,
91 tok::star, tok::amp, tok::ampamp, tok::less,
96 return Tok == MI->tokens_end() ||
97 Tok->isOneOf(tok::equal, tok::semi, tok::l_square, tok::l_paren) ||
101void MacroParenthesesPPCallbacks::replacementList(
const Token &MacroNameTok,
102 const MacroInfo *MI) {
113 for (
auto TI = MI->tokens_begin(), TE = MI->tokens_end(); TI != TE; ++TI) {
114 const Token &Tok = *TI;
119 if (Count == 0 && Tok.isOneOf(tok::comma, tok::semi))
121 if (Tok.isOneOf(tok::l_paren, tok::l_brace, tok::l_square)) {
123 }
else if (Tok.isOneOf(tok::r_paren, tok::r_brace, tok::r_square)) {
128 }
else if (Count == 0 &&
isWarnOp(Tok)) {
132 if (TI == MI->tokens_begin() && (TI + 1) != TE &&
133 !Tok.isOneOf(tok::plus, tok::minus))
137 if ((TE - 1)->is(tok::star))
140 Loc = Tok.getLocation();
144 const Token &Last = *(MI->tokens_end() - 1);
145 Check->diag(
Loc,
"macro replacement list should be enclosed in parentheses")
146 << FixItHint::CreateInsertion(MI->tokens_begin()->getLocation(),
"(")
147 << FixItHint::CreateInsertion(Last.getLocation().getLocWithOffset(
148 PP->getSpelling(Last).length()),
153void MacroParenthesesPPCallbacks::argument(
const Token &MacroNameTok,
154 const MacroInfo *MI) {
160 bool FoundGoto =
false;
162 for (
auto TI = MI->tokens_begin(), TE = MI->tokens_end(); TI != TE; ++TI) {
164 if (TI == MI->tokens_begin())
168 if ((TI + 1) == MI->tokens_end())
171 const Token &Prev = *(TI - 1);
172 const Token &Next = *(TI + 1);
174 const Token &Tok = *TI;
178 if (Tok.isOneOf(tok::equal, tok::semi, tok::l_square, tok::l_paren))
184 if (Tok.is(tok::kw_goto)) {
190 if (!Tok.isOneOf(tok::identifier, tok::raw_identifier)) {
196 if (MI->getParameterNum(Tok.getIdentifierInfo()) < 0)
204 if (Prev.isOneOf(tok::hash, tok::hashhash) || Next.is(tok::hashhash))
208 if (Prev.isOneOf(tok::period, tok::arrow, tok::coloncolon, tok::arrowstar,
213 if (Next.is(tok::coloncolon))
217 if (isStringLiteral(Prev.getKind()) || isStringLiteral(Next.getKind()))
221 if (isAnyIdentifier(Prev.getKind()) ||
isKeyword(Prev) ||
222 isAnyIdentifier(Next.getKind()) ||
isKeyword(Next))
226 if (Next.is(tok::l_paren))
230 if (Prev.is(tok::l_paren) && Next.is(tok::star) &&
231 TI + 2 != MI->tokens_end() && (TI + 2)->is(tok::r_paren))
235 if (Prev.isOneOf(tok::equal, tok::kw_return) && Next.is(tok::semi))
239 if (
PP->getLangOpts().CPlusPlus && Prev.isOneOf(tok::comma, tok::less) &&
240 Next.isOneOf(tok::comma, tok::greater))
244 if (Prev.is(tok::kw_namespace))
248 if (MI->isVariadic())
252 Check->diag(Tok.getLocation(),
"macro argument should be enclosed in "
254 << FixItHint::CreateInsertion(Tok.getLocation(),
"(")
255 << FixItHint::CreateInsertion(Tok.getLocation().getLocWithOffset(
256 PP->getSpelling(Tok).length()),
265 const SourceManager &SM, Preprocessor *
PP, Preprocessor *ModuleExpanderPP) {
266 PP->addPPCallbacks(std::make_unique<MacroParenthesesPPCallbacks>(
PP,
this));
void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) override
Override this to register PPCallbacks in the preprocessor.
static bool isKeyword(const Token &T)
Is given TokenKind a keyword?
static bool isSurroundedRight(const Token &T)
Is argument surrounded properly with parentheses/braces/squares/commas?
static bool isWarnOp(const Token &T)
Warning is written when one of these operators are not within parentheses.
static bool isVarDeclKeyword(const Token &T)
Is given Token a keyword that is used in variable declarations?
static bool isSurroundedLeft(const Token &T)
Is argument surrounded properly with parentheses/braces/squares/commas?
static bool possibleVarDecl(const MacroInfo *MI, const Token *Tok)
Is there a possible variable declaration at Tok?