| 5666 | } |
| 5667 | |
| 5668 | static void valueFlowSubFunction(const TokenList& tokenlist, |
| 5669 | const SymbolDatabase& symboldatabase, |
| 5670 | ErrorLogger& errorLogger, |
| 5671 | const Settings& settings) |
| 5672 | { |
| 5673 | int id = 0; |
| 5674 | for (auto it = symboldatabase.functionScopes.crbegin(); it != symboldatabase.functionScopes.crend(); ++it) { |
| 5675 | const Scope* scope = *it; |
| 5676 | const Function* function = scope->function; |
| 5677 | if (!function) |
| 5678 | continue; |
| 5679 | for (auto* tok = const_cast<Token*>(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) { |
| 5680 | if (tok->isKeyword() || !Token::Match(tok, "%name% (")) |
| 5681 | continue; |
| 5682 | |
| 5683 | const Function* const calledFunction = tok->function(); |
| 5684 | if (!calledFunction) { |
| 5685 | // library function? |
| 5686 | const std::string& returnValue(settings.library.returnValue(tok)); |
| 5687 | if (!returnValue.empty()) |
| 5688 | valueFlowLibraryFunction(tok->next(), returnValue, settings); |
| 5689 | continue; |
| 5690 | } |
| 5691 | |
| 5692 | const Scope* const calledFunctionScope = calledFunction->functionScope; |
| 5693 | if (!calledFunctionScope) |
| 5694 | continue; |
| 5695 | |
| 5696 | id++; |
| 5697 | std::unordered_map<const Variable*, std::list<ValueFlow::Value>> argvars; |
| 5698 | // TODO: Rewrite this. It does not work well to inject 1 argument at a time. |
| 5699 | const std::vector<const Token*>& callArguments = getArguments(tok); |
| 5700 | for (int argnr = 0U; argnr < callArguments.size(); ++argnr) { |
| 5701 | const Token* argtok = callArguments[argnr]; |
| 5702 | // Get function argument |
| 5703 | const Variable* const argvar = calledFunction->getArgumentVar(argnr); |
| 5704 | if (!argvar) |
| 5705 | break; |
| 5706 | |
| 5707 | // passing value(s) to function |
| 5708 | std::list<ValueFlow::Value> argvalues(getFunctionArgumentValues(argtok)); |
| 5709 | |
| 5710 | // Remove non-local lifetimes |
| 5711 | argvalues.remove_if([](const ValueFlow::Value& v) { |
| 5712 | if (v.isLifetimeValue()) |
| 5713 | return !v.isLocalLifetimeValue() && !v.isSubFunctionLifetimeValue(); |
| 5714 | return false; |
| 5715 | }); |
| 5716 | // Remove uninit values if argument is passed by value |
| 5717 | if (argtok->variable() && !argtok->variable()->isPointer() && argvalues.size() == 1 && |
| 5718 | argvalues.front().isUninitValue()) { |
| 5719 | if (CheckUninitVarImpl::isVariableUsage(argtok, settings.library, false, CheckUninitVarImpl::Alloc::NO_ALLOC, 0)) |
| 5720 | continue; |
| 5721 | } |
| 5722 | |
| 5723 | if (argvalues.empty()) |
| 5724 | continue; |
| 5725 |
no test coverage detected