@@ -36,66 +36,50 @@ void CheckAssert::assertWithSideEffects()
3636 if (!_settings->isEnabled (" warning" ))
3737 return ;
3838
39- const Token *tok = findAssertPattern (_tokenizer->tokens ());
40- const Token *endTok = tok ? tok->next ()->link () : nullptr ;
39+ for (const Token* tok = _tokenizer->list .front (); tok; tok = tok->next ()) {
40+ if (!Token::simpleMatch (tok, " assert (" ))
41+ continue ;
4142
42- while (tok && endTok) {
43+ const Token * endTok = tok-> next ()-> link ();
4344 for (const Token* tmp = tok->next (); tmp != endTok; tmp = tmp->next ()) {
44- checkVariableAssignment (tmp, true );
45+ checkVariableAssignment (tmp);
4546
46- if (tmp->isName () && tmp-> type () == Token::eFunction) {
47+ if (tmp->type () == Token::eFunction) {
4748 const Function* f = tmp->function ();
48- if (f->argCount () == 0 && f->isConst ) continue ;
49-
50- // functions with non-const references
51- else if (f->argCount () != 0 ) {
52- for (std::list<Variable>::const_iterator it = f->argumentList .begin (); it != f->argumentList .end (); ++it) {
53- if (it->isConst () || it->isLocal ()) continue ;
54- else if (it->isReference ()) {
55- const Token* next = it->nameToken ()->next ();
56- bool isAssigned = checkVariableAssignment (next, false );
57- if (isAssigned)
58- sideEffectInAssertError (tmp, f->name ());
59- continue ;
60- }
61- }
62- }
6349
64- // variables in function scope
65- const Scope* scope = f->functionScope ;
66- if (!scope) continue ;
67-
68- for (const Token *tok2 = scope->classStart ; tok2 != scope->classEnd ; tok2 = tok2->next ()) {
69- if (tok2->type () != Token::eAssignmentOp && tok2->type () != Token::eIncDecOp) continue ;
70- const Variable* var = tok2->previous ()->variable ();
71- if (!var || var->isLocal ()) continue ;
72- if (var->isArgument () &&
73- (var->isConst () || (!var->isReference () && !var->isPointer ())))
74- // see ticket #4937. Assigning function arguments not passed by reference is ok.
75- continue ;
76- std::vector<const Token*> returnTokens; // find all return statements
77- for (const Token *rt = scope->classStart ; rt != scope->classEnd ; rt = rt->next ()) {
78- if (!Token::Match (rt, " return %any%" )) continue ;
79- returnTokens.push_back (rt);
80- }
50+ if (f->nestedIn ->isClassOrStruct () && !f->isStatic && !f->isConst )
51+ sideEffectInAssertError (tmp, f->name ()); // Non-const member function called
52+ else {
53+ const Scope* scope = f->functionScope ;
54+ if (!scope) continue ;
55+
56+ for (const Token *tok2 = scope->classStart ; tok2 != scope->classEnd ; tok2 = tok2->next ()) {
57+ if (tok2->type () != Token::eAssignmentOp && tok2->type () != Token::eIncDecOp)
58+ continue ;
8159
82- bool noReturnInScope = true ;
83- for (std::vector<const Token*>::iterator rt = returnTokens.begin (); rt != returnTokens.end (); ++rt) {
84- if (inSameScope (*rt, tok2)) {
85- noReturnInScope = false ;
86- break ;
60+ const Variable* var = tok2->previous ()->variable ();
61+ if (!var || var->isLocal () || (var->isArgument () && !var->isReference () && !var->isPointer ()))
62+ continue ; // See ticket #4937. Assigning function arguments not passed by reference is ok.
63+ if (var->isArgument () && var->isPointer () && tok2->strAt (-2 ) != " *" )
64+ continue ; // Pointers need to be dereferenced, otherwise there is no error
65+
66+ bool noReturnInScope = true ;
67+ for (const Token *rt = scope->classStart ; rt != scope->classEnd ; rt = rt->next ()) {
68+ if (rt->str () != " return" ) continue ; // find all return statements
69+ if (inSameScope (rt, tok2)) {
70+ noReturnInScope = false ;
71+ break ;
72+ }
8773 }
88- }
89- if (noReturnInScope) continue ;
90- bool isAssigned = checkVariableAssignment (tok2, false );
91- if (isAssigned)
74+ if (noReturnInScope) continue ;
75+
9276 sideEffectInAssertError (tmp, f->name ());
77+ break ;
78+ }
9379 }
9480 }
9581 }
96-
97- tok = findAssertPattern (endTok->next ());
98- endTok = tok ? tok->next ()->link () : nullptr ;
82+ tok = endTok;
9983 }
10084}
10185// ---------------------------------------------------------------------------
@@ -122,30 +106,21 @@ void CheckAssert::assignmentInAssertError(const Token *tok, const std::string& v
122106}
123107
124108// checks if side effects happen on the variable prior to tmp
125- bool CheckAssert::checkVariableAssignment (const Token* assignTok, bool reportErr /* = true */ )
109+ void CheckAssert::checkVariableAssignment (const Token* assignTok)
126110{
127111 const Variable* v = assignTok->previous ()->variable ();
128- if (!v) return false ;
112+ if (!v) return ;
129113
130114 // assignment
131115 if (assignTok->isAssignmentOp () || assignTok->type () == Token::eIncDecOp) {
132116
133- if (v->isConst ()) return false ;
134-
135- if (reportErr) // report as variable assignment error
136- assignmentInAssertError (assignTok, v->name ());
117+ if (v->isConst ()) return ;
137118
138- return true ;
119+ assignmentInAssertError (assignTok, v-> name ()) ;
139120 }
140- return false ;
141121 // TODO: function calls on v
142122}
143123
144- const Token* CheckAssert::findAssertPattern (const Token* start)
145- {
146- return Token::findmatch (start, " assert ( %any%" );
147- }
148-
149124bool CheckAssert::inSameScope (const Token* returnTok, const Token* assignTok)
150125{
151126 // TODO: even if a return is in the same scope, the assignment might not affect it.
0 commit comments