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

Method isFunctionWithoutSideEffects

lib/symboldatabase.cpp:2222–2298  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

2220}
2221
2222bool SymbolDatabase::isFunctionWithoutSideEffects(const Function& func, const Token* functionUsageToken, std::list<const Function*> checkedFuncs) const
2223{
2224 // no body to analyze
2225 if (!func.hasBody()) {
2226 return false;
2227 }
2228
2229 for (const Token* argsToken = functionUsageToken->next(); !Token::simpleMatch(argsToken, ")"); argsToken = argsToken->next()) {
2230 const Variable* argVar = argsToken->variable();
2231 if (argVar && argVar->isGlobal()) {
2232 return false; // TODO: analyze global variable usage
2233 }
2234 }
2235
2236 bool sideEffectReturnFound = false;
2237 std::set<const Variable*> pointersToGlobals;
2238 for (const Token* bodyToken = func.functionScope->bodyStart->next(); bodyToken != func.functionScope->bodyEnd;
2239 bodyToken = bodyToken->next()) {
2240 // check variable inside function body
2241 const Variable* bodyVariable = bodyToken->variable();
2242 if (bodyVariable) {
2243 if (!isVariableWithoutSideEffects(*bodyVariable)) {
2244 return false;
2245 }
2246 // check if global variable is changed
2247 if (bodyVariable->isGlobal() || (pointersToGlobals.find(bodyVariable) != pointersToGlobals.end())) {
2248 const int indirect = bodyVariable->isArray() ? bodyVariable->dimensions().size() : bodyVariable->isPointer();
2249 if (isVariableChanged(bodyToken, indirect, mSettings)) {
2250 return false;
2251 }
2252 // check if pointer to global variable assigned to another variable (another_var = &global_var)
2253 if (Token::simpleMatch(bodyToken->tokAt(-1), "&") && Token::simpleMatch(bodyToken->tokAt(-2), "=")) {
2254 const Token* assigned_var_token = bodyToken->tokAt(-3);
2255 if (assigned_var_token && assigned_var_token->variable()) {
2256 pointersToGlobals.insert(assigned_var_token->variable());
2257 }
2258 }
2259 }
2260 }
2261
2262 // check nested function
2263 const Function* bodyFunction = bodyToken->function();
2264 if (bodyFunction) {
2265 if (std::find(checkedFuncs.cbegin(), checkedFuncs.cend(), bodyFunction) != checkedFuncs.cend()) { // recursion found
2266 continue;
2267 }
2268 checkedFuncs.push_back(bodyFunction);
2269 if (!isFunctionWithoutSideEffects(*bodyFunction, bodyToken, checkedFuncs)) {
2270 return false;
2271 }
2272 }
2273
2274 // check returned value
2275 if (Token::simpleMatch(bodyToken, "return")) {
2276 const Token* returnValueToken = bodyToken->next();
2277 // TODO: handle complex return expressions
2278 if (!Token::simpleMatch(returnValueToken->next(), ";")) {
2279 sideEffectReturnFound = true;

Callers

nothing calls this directly

Calls 12

isVariableChangedFunction · 0.85
nextMethod · 0.80
variableMethod · 0.80
isArrayMethod · 0.80
simpleMatchFunction · 0.70
isGlobalMethod · 0.45
findMethod · 0.45
endMethod · 0.45
sizeMethod · 0.45
tokAtMethod · 0.45
functionMethod · 0.45
push_backMethod · 0.45

Tested by

no test coverage detected