MCPcopy Create free account
hub / github.com/cppcheck-opensource/cppcheck / expandHashHash

Method expandHashHash

externals/simplecpp/simplecpp.cpp:2308–2419  ·  view source on GitHub ↗

* 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

Source from the content-addressed store, hash-verified

2306 * @return token after B
2307 */
2308 const Token *expandHashHash(TokenList &output, const Location &loc, const Token *tok, const MacroMap &macros, const std::set<TokenString> &expandedmacros, const std::vector<const Token*> &parametertokens, 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());

Callers

nothing calls this directly

Calls 14

invalidHashHashClass · 0.85
isOneOfMethod · 0.80
frontMethod · 0.80
deleteTokenMethod · 0.80
functionLikeMethod · 0.80
samelineFunction · 0.70
isStringLiteralFunction · 0.70
isCharLiteralFunction · 0.70
strMethod · 0.45
emptyMethod · 0.45
push_backMethod · 0.45
sizeMethod · 0.45

Tested by

no test coverage detected