Skip to content

Commit c764bc8

Browse files
dmcppcheckclaude
andcommitted
Move the argument count check into Macro::getMacroParameters()
Check the number of arguments where they are read instead of in the caller. Add a test for calls with the wrong number of arguments. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
1 parent 567b72b commit c764bc8

2 files changed

Lines changed: 67 additions & 19 deletions

File tree

‎simplecpp.cpp‎

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2204,10 +2204,33 @@ namespace simplecpp {
22042204
return ~0U;
22052205
}
22062206

2207+
/**
2208+
* Find the arguments of a call of this macro.
2209+
* @param nameTokInst the macro name in the call
2210+
* @param calledInDefine the call is in a #define, so the arguments must be on the same line
2211+
* @return the tokens that delimit the arguments: the '(', each ',' between two arguments and the ')'.
2212+
* Empty when the macro is not function-like or the name is not followed by '('.
2213+
* @throws wrongNumberOfParameters if a function-like macro has the wrong number of arguments
2214+
*/
22072215
std::vector<const Token *> getMacroParameters(const Token *nameTokInst, bool calledInDefine) const {
2208-
if (!nameTokInst->next || nameTokInst->next->op != '(' || !functionLike())
2216+
if (!functionLike())
22092217
return {};
2218+
std::vector<const Token *> parametertokens;
2219+
if (nameTokInst->next && nameTokInst->next->op == '(')
2220+
parametertokens = findArgumentDelimiters(nameTokInst, calledInDefine);
2221+
2222+
if (variadic) {
2223+
if (parametertokens.size() < args.size())
2224+
throw wrongNumberOfParameters(nameTokInst->location, name());
2225+
} else {
2226+
if (parametertokens.size() != args.size() + (args.empty() ? 2U : 1U))
2227+
throw wrongNumberOfParameters(nameTokInst->location, name());
2228+
}
2229+
return parametertokens;
2230+
}
22102231

2232+
/** The '(', each ',' between two arguments and the ')' of the call. nameTokInst is followed by '('. */
2233+
std::vector<const Token *> findArgumentDelimiters(const Token *nameTokInst, bool calledInDefine) const {
22112234
std::vector<const Token *> parametertokens;
22122235
parametertokens.emplace_back(nameTokInst->next);
22132236
unsigned int par = 0U;
@@ -2296,26 +2319,14 @@ namespace simplecpp {
22962319
const bool calledInDefine = (loc.fileIndex != nameTokInst->location.fileIndex ||
22972320
loc.line < nameTokInst->location.line);
22982321

2299-
std::vector<const Token*> parametertokens1(getMacroParameters(nameTokInst, calledInDefine));
2300-
2301-
if (functionLike()) {
2302-
// No arguments => not macro expansion
2303-
if (nameTokInst->next && nameTokInst->next->op != '(') {
2304-
output.push_back(new Token(nameTokInst->str(), loc));
2305-
return nameTokInst->next;
2306-
}
2307-
2308-
// Parse macro-call
2309-
if (variadic) {
2310-
if (parametertokens1.size() < args.size()) {
2311-
throw wrongNumberOfParameters(nameTokInst->location, name());
2312-
}
2313-
} else {
2314-
if (parametertokens1.size() != args.size() + (args.empty() ? 2U : 1U))
2315-
throw wrongNumberOfParameters(nameTokInst->location, name());
2316-
}
2322+
// No arguments => not macro expansion
2323+
if (functionLike() && nameTokInst->next && nameTokInst->next->op != '(') {
2324+
output.push_back(new Token(nameTokInst->str(), loc));
2325+
return nameTokInst->next;
23172326
}
23182327

2328+
std::vector<const Token*> parametertokens1(getMacroParameters(nameTokInst, calledInDefine));
2329+
23192330
// If macro call uses __COUNTER__ then expand that first
23202331
TokenList tokensparams(files);
23212332
std::vector<const Token *> parametertokens2;

‎test.cpp‎

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1161,6 +1161,42 @@ static void define_invalid_3()
11611161
TODO_ASSERT_EQUALS("", "file0,2,syntax_error,failed to expand 'R', Wrong number of parameters for macro 'R'.\n", toString(outputList));
11621162
}
11631163

1164+
static void define_wrong_number_of_arguments()
1165+
{
1166+
{
1167+
simplecpp::OutputList outputList;
1168+
ASSERT_EQUALS("", preprocess("#define f(a,b) a+b\nf(1)\n", &outputList));
1169+
ASSERT_EQUALS("file0,2,syntax_error,failed to expand 'f', Wrong number of parameters for macro 'f'.\n", toString(outputList));
1170+
}
1171+
{
1172+
simplecpp::OutputList outputList;
1173+
ASSERT_EQUALS("", preprocess("#define f(a,b) a+b\nf(1,2,3)\n", &outputList));
1174+
ASSERT_EQUALS("file0,2,syntax_error,failed to expand 'f', Wrong number of parameters for macro 'f'.\n", toString(outputList));
1175+
}
1176+
{
1177+
simplecpp::OutputList outputList;
1178+
ASSERT_EQUALS("", preprocess("#define f(a,b,...) a+b\nf(1)\n", &outputList));
1179+
ASSERT_EQUALS("file0,2,syntax_error,failed to expand 'f', Wrong number of parameters for macro 'f'.\n", toString(outputList));
1180+
}
1181+
{
1182+
simplecpp::OutputList outputList;
1183+
ASSERT_EQUALS("\n1", preprocess("#define f(a,...) a __VA_ARGS__\nf(1)\n", &outputList));
1184+
ASSERT_EQUALS("", toString(outputList));
1185+
}
1186+
{
1187+
// a function-like macro name that is not followed by ( is not expanded
1188+
simplecpp::OutputList outputList;
1189+
ASSERT_EQUALS("\nf ;", preprocess("#define f(a) a\nf;\n", &outputList));
1190+
ASSERT_EQUALS("", toString(outputList));
1191+
}
1192+
{
1193+
// TODO: f takes no arguments, gcc reports an error
1194+
simplecpp::OutputList outputList;
1195+
TODO_ASSERT_EQUALS("", "\n1", preprocess("#define f() 1\nf(1)\n", &outputList));
1196+
TODO_ASSERT_EQUALS("file0,2,syntax_error,failed to expand 'f', Wrong number of parameters for macro 'f'.\n", "", toString(outputList));
1197+
}
1198+
}
1199+
11641200
static void define_invalid_4()
11651201
{
11661202
const char code[] = "#define X(...)\n"
@@ -5546,6 +5582,7 @@ static void runTests(int argc, char **argv, Input input)
55465582
TEST_CASE(define_invalid_2);
55475583
TEST_CASE(define_invalid_3);
55485584
TEST_CASE(define_invalid_4);
5585+
TEST_CASE(define_wrong_number_of_arguments);
55495586
TEST_CASE(define_define_1);
55505587
TEST_CASE(define_define_2);
55515588
TEST_CASE(define_define_3);

0 commit comments

Comments
 (0)