* Expand A##B => AB * The A should already be expanded. Call this when you reach the first # token * @param output destination tokenlist * @param loc location for expanded token * @param tok first # token * @param macros all macros * @param expandedmacros set with expanded macros, with this macro * @param parametertokens p
| 2306 | * @return token after B |
| 2307 | */ |
| 2308 | const Token *expandHashHash(TokenList &output, const Location &loc, const Token *tok, const MacroMap ¯os, const std::set<TokenString> &expandedmacros, const std::vector<const Token*> ¶metertokens, bool expandResult=true) const { |
| 2309 | Token *A = output.back(); |
| 2310 | if (!A) |
| 2311 | throw invalidHashHash(tok->location, name(), "Missing first argument"); |
| 2312 | if (!sameline(tok, tok->next) || !sameline(tok, tok->next->next)) |
| 2313 | throw invalidHashHash::unexpectedNewline(tok->location, name()); |
| 2314 | |
| 2315 | const bool canBeConcatenatedWithEqual = A->isOneOf("+-*/%&|^") || A->str() == "<<" || A->str() == ">>"; |
| 2316 | const bool canBeConcatenatedStringOrChar = isStringLiteral(A->str()) || isCharLiteral(A->str()); |
| 2317 | const bool unexpectedA = (!A->name && !A->number && !A->str().empty() && !canBeConcatenatedWithEqual && !canBeConcatenatedStringOrChar); |
| 2318 | |
| 2319 | const Token * const B = tok->next->next; |
| 2320 | if (!B->name && !B->number && B->op && !B->isOneOf("#=")) |
| 2321 | throw invalidHashHash::unexpectedToken(tok->location, name(), B); |
| 2322 | |
| 2323 | if ((canBeConcatenatedWithEqual && B->op != '=') || |
| 2324 | (!canBeConcatenatedWithEqual && B->op == '=')) |
| 2325 | throw invalidHashHash::cannotCombine(tok->location, name(), A, B); |
| 2326 | |
| 2327 | // Superficial check; more in-depth would in theory be possible _after_ expandArg |
| 2328 | if (canBeConcatenatedStringOrChar && (B->number || !B->name)) |
| 2329 | throw invalidHashHash::cannotCombine(tok->location, name(), A, B); |
| 2330 | |
| 2331 | TokenList tokensB(files); |
| 2332 | const Token *nextTok = B->next; |
| 2333 | |
| 2334 | if (canBeConcatenatedStringOrChar) { |
| 2335 | if (unexpectedA) |
| 2336 | throw invalidHashHash::unexpectedToken(tok->location, name(), A); |
| 2337 | |
| 2338 | // It seems clearer to handle this case separately even though the code is similar-ish, but we don't want to merge here. |
| 2339 | // TODO The question is whether the ## or varargs may still apply, and how to provoke? |
| 2340 | if (expandArg(tokensB, B, parametertokens)) { |
| 2341 | for (Token *b = tokensB.front(); b; b = b->next) |
| 2342 | b->location = loc; |
| 2343 | } else { |
| 2344 | tokensB.push_back(new Token(*B)); |
| 2345 | tokensB.back()->location = loc; |
| 2346 | } |
| 2347 | output.takeTokens(tokensB); |
| 2348 | } else { |
| 2349 | std::string strAB; |
| 2350 | |
| 2351 | const bool varargs = variadic && !args.empty() && B->str() == args[args.size()-1U]; |
| 2352 | |
| 2353 | if (expandArg(tokensB, B, parametertokens)) { |
| 2354 | if (tokensB.empty()) { |
| 2355 | strAB = A->str(); |
| 2356 | } |
| 2357 | else if (varargs && A->op == ',') { |
| 2358 | strAB = ","; |
| 2359 | } |
| 2360 | else if (varargs && unexpectedA) { |
| 2361 | throw invalidHashHash::unexpectedToken(tok->location, name(), A); |
| 2362 | } |
| 2363 | else { |
| 2364 | strAB = A->str() + tokensB.cfront()->str(); |
| 2365 | tokensB.deleteToken(tokensB.front()); |
nothing calls this directly
no test coverage detected