| 2485 | } |
| 2486 | |
| 2487 | bool CheckClassImpl::checkConstFunc(const Scope *scope, const Function *func, MemberAccess& memberAccessed) const |
| 2488 | { |
| 2489 | if (mTokenizer->hasIfdef(func->functionScope->bodyStart, func->functionScope->bodyEnd)) |
| 2490 | return false; |
| 2491 | |
| 2492 | auto getFuncTok = [](const Token* tok) -> const Token* { |
| 2493 | if (Token::simpleMatch(tok, "this")) |
| 2494 | tok = getFuncTokFromThis(tok); |
| 2495 | bool isReturn = false; |
| 2496 | if ((Token::Match(tok, "%name% (|{") || (isReturn = Token::simpleMatch(tok->astParent(), "return {"))) && !tok->isStandardType() && !tok->isKeyword()) { |
| 2497 | if (isReturn) |
| 2498 | tok = tok->astParent(); |
| 2499 | return tok; |
| 2500 | } |
| 2501 | return nullptr; |
| 2502 | }; |
| 2503 | |
| 2504 | auto checkFuncCall = [this, &memberAccessed](const Token* funcTok, const Scope* scope, const Function* func) { |
| 2505 | if (isMemberFunc(scope, funcTok) && (funcTok->strAt(-1) != "." || Token::simpleMatch(funcTok->tokAt(-2), "this ."))) { |
| 2506 | const bool isSelf = func == funcTok->function(); |
| 2507 | if (!isConstMemberFunc(scope, funcTok) && !isSelf) |
| 2508 | return false; |
| 2509 | memberAccessed = (isSelf && memberAccessed != MemberAccess::MEMBER) ? MemberAccess::SELF : MemberAccess::MEMBER; |
| 2510 | } |
| 2511 | |
| 2512 | if (const Function* f = funcTok->function()) { // check known function |
| 2513 | const std::vector<const Token*> args = getArguments(funcTok); |
| 2514 | const auto argMax = std::min<nonneg int>(args.size(), f->argCount()); |
| 2515 | |
| 2516 | for (nonneg int argIndex = 0; argIndex < argMax; ++argIndex) { |
| 2517 | const Variable* const argVar = f->getArgumentVar(argIndex); |
| 2518 | if (!argVar || ((argVar->isArrayOrPointer() || argVar->isReference()) && |
| 2519 | !(argVar->valueType() && argVar->valueType()->isConst(argVar->valueType()->pointer)))) { // argument might be modified |
| 2520 | const Token* arg = args[argIndex]; |
| 2521 | // Member variable given as parameter |
| 2522 | while (Token::simpleMatch(arg, "(") && arg->astOperand2()) |
| 2523 | arg = arg->astOperand2(); |
| 2524 | const Token* varTok = previousBeforeAstLeftmostLeaf(arg); |
| 2525 | if (!varTok) |
| 2526 | return false; |
| 2527 | varTok = varTok->next(); |
| 2528 | if ((varTok->isName() && isMemberVar(scope, varTok)) || (varTok->isUnaryOp("&") && (varTok = varTok->astOperand1()) && isMemberVar(scope, varTok))) { |
| 2529 | const Variable* var = varTok->variable(); |
| 2530 | if (!var || (!var->isMutable() && !var->isConst())) |
| 2531 | return false; |
| 2532 | } |
| 2533 | } |
| 2534 | } |
| 2535 | return true; |
| 2536 | } |
| 2537 | |
| 2538 | if (const Library::Function* fLib = mSettings.library.getFunction(funcTok)) |
| 2539 | if (fLib->isconst || fLib->ispure) |
| 2540 | return true; |
| 2541 | |
| 2542 | // Member variable given as parameter to unknown function |
| 2543 | const Token *lpar = funcTok->next(); |
| 2544 | if (Token::simpleMatch(lpar, "( ) (")) |
nothing calls this directly
no test coverage detected