@@ -347,8 +347,10 @@ static bool hasToken(const Token * startTok, const Token * stopTok, const Token
347347template <class T , REQUIRES(" T must be a Token class" , std::is_convertible<T*, const Token*>)>
348348static T* previousBeforeAstLeftmostLeafGeneric (T* tok)
349349{
350+ if (!tok)
351+ return nullptr ;
350352 T* leftmostLeaf = tok;
351- while (leftmostLeaf && leftmostLeaf ->astOperand1 ())
353+ while (leftmostLeaf->astOperand1 ())
352354 leftmostLeaf = leftmostLeaf->astOperand1 ();
353355 return leftmostLeaf->previous ();
354356}
@@ -1392,14 +1394,96 @@ bool isOppositeExpression(bool cpp, const Token * const tok1, const Token * cons
13921394 return false ;
13931395}
13941396
1397+ static bool functionModifiesArguments (const Function* f)
1398+ {
1399+ return std::any_of (f->argumentList .begin (), f->argumentList .end (), [](const Variable& var) {
1400+ if (var.isReference () || var.isPointer ())
1401+ return !var.isConst ();
1402+ return true ;
1403+ });
1404+ }
1405+
1406+ bool isConstFunctionCall (const Token* ftok, const Library& library)
1407+ {
1408+ if (!Token::Match (ftok, " %name% (" ))
1409+ return false ;
1410+ if (const Function* f = ftok->function ()) {
1411+ if (f->isAttributePure () || f->isAttributeConst ())
1412+ return true ;
1413+ if (Function::returnsVoid (f))
1414+ return false ;
1415+ // Any modified arguments
1416+ if (functionModifiesArguments (f))
1417+ return false ;
1418+ // Member function call
1419+ if (Token::simpleMatch (ftok->previous (), " ." )) {
1420+ if (f->isConst ())
1421+ return true ;
1422+ // Check for const overloaded function that just return the const version
1423+ if (!Function::returnsConst (f)) {
1424+ std::vector<const Function*> fs = f->getOverloadedFunctions ();
1425+ if (std::any_of (fs.begin (), fs.end (), [&](const Function* g) {
1426+ if (f == g)
1427+ return false ;
1428+ if (f->argumentList .size () != g->argumentList .size ())
1429+ return false ;
1430+ if (functionModifiesArguments (g))
1431+ return false ;
1432+ if (g->isConst () && Function::returnsConst (g))
1433+ return true ;
1434+ return false ;
1435+ }))
1436+ return true ;
1437+ }
1438+ return false ;
1439+ } else if (f->argumentList .empty ()) {
1440+ // TODO: Check for constexpr
1441+ return false ;
1442+ }
1443+ } else if (const Library::Function* f = library.getFunction (ftok)) {
1444+ if (f->ispure )
1445+ return true ;
1446+ for (auto && p : f->argumentChecks ) {
1447+ const Library::ArgumentChecks& ac = p.second ;
1448+ if (ac.direction != Library::ArgumentChecks::Direction::DIR_IN)
1449+ return false ;
1450+ }
1451+ if (Token::simpleMatch (ftok->previous (), " ." )) {
1452+ if (!f->isconst )
1453+ return false ;
1454+ } else if (f->argumentChecks .empty ()) {
1455+ return false ;
1456+ }
1457+ } else {
1458+ bool memberFunction = Token::Match (ftok->previous (), " . %name% (" );
1459+ bool constMember = !memberFunction;
1460+ if (Token::Match (ftok->tokAt (-2 ), " %var% . %name% (" )) {
1461+ const Variable* var = ftok->tokAt (-2 )->variable ();
1462+ if (var)
1463+ constMember = var->isConst ();
1464+ }
1465+ // TODO: Only check const on lvalues
1466+ std::vector<const Token*> args = getArguments (ftok);
1467+ if (memberFunction && args.empty ())
1468+ return false ;
1469+ return constMember && std::all_of (args.begin (), args.end (), [](const Token* tok) {
1470+ const Variable* var = tok->variable ();
1471+ if (var)
1472+ return var->isConst ();
1473+ return false ;
1474+ });
1475+ }
1476+ return true ;
1477+ }
1478+
13951479bool isConstExpression (const Token *tok, const Library& library, bool pure, bool cpp)
13961480{
13971481 if (!tok)
13981482 return true ;
1483+ if (tok->variable () && tok->variable ()->isVolatile ())
1484+ return false ;
13991485 if (tok->isName () && tok->next ()->str () == " (" ) {
1400- if (!tok->function () && !Token::Match (tok->previous (), " .|::" ) && !library.isFunctionConst (tok->str (), pure))
1401- return false ;
1402- else if (tok->function () && !tok->function ()->isConst ())
1486+ if (!isConstFunctionCall (tok, library))
14031487 return false ;
14041488 }
14051489 if (tok->tokType () == Token::eIncDecOp)
@@ -1880,6 +1964,9 @@ bool isVariableChanged(const Token *tok, int indirect, const Settings *settings,
18801964 // Member function call
18811965 if (tok->variable () && Token::Match (tok2->astParent (), " . %name%" ) && isFunctionCall (tok2->astParent ()->next ()) && tok2->astParent ()->astOperand1 () == tok2) {
18821966 const Variable * var = tok->variable ();
1967+ // Member function cannot change what `this` points to
1968+ if (indirect == 0 && astIsPointer (tok))
1969+ return false ;
18831970 bool isConst = var && var->isConst ();
18841971 if (!isConst) {
18851972 const ValueType * valueType = var->valueType ();
@@ -2092,24 +2179,28 @@ bool isVariablesChanged(const Token* start,
20922179 return false ;
20932180}
20942181
2182+ bool isThisChanged (const Token* tok, int indirect, const Settings* settings, bool cpp)
2183+ {
2184+ if (Token::Match (tok->previous (), " %name% (" )) {
2185+ if (tok->previous ()->function ()) {
2186+ return (!tok->previous ()->function ()->isConst ());
2187+ } else if (!tok->previous ()->isKeyword ()) {
2188+ return true ;
2189+ }
2190+ }
2191+ if (isVariableChanged (tok, indirect, settings, cpp))
2192+ return true ;
2193+ return false ;
2194+ }
2195+
20952196bool isThisChanged (const Token* start, const Token* end, int indirect, const Settings* settings, bool cpp)
20962197{
20972198 if (!precedes (start, end))
20982199 return false ;
20992200 for (const Token* tok = start; tok != end; tok = tok->next ()) {
21002201 if (!exprDependsOnThis (tok))
21012202 continue ;
2102- if (Token::Match (tok->previous (), " %name% (" )) {
2103- if (tok->previous ()->function ()) {
2104- if (!tok->previous ()->function ()->isConst ())
2105- return true ;
2106- else
2107- continue ;
2108- } else if (!tok->previous ()->isKeyword ()) {
2109- return true ;
2110- }
2111- }
2112- if (isVariableChanged (tok, indirect, settings, cpp))
2203+ if (isThisChanged (tok, indirect, settings, cpp))
21132204 return true ;
21142205 }
21152206 return false ;
0 commit comments