Skip to content

Commit a6f4fba

Browse files
authored
Fix issue 2741: False negative: redundant assignment of x to itself (ref = x) (#3071)
1 parent 0fa89ff commit a6f4fba

2 files changed

Lines changed: 83 additions & 0 deletions

File tree

lib/astutils.cpp

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "astutils.h"
2222

2323
#include "config.h"
24+
#include "errortypes.h"
2425
#include "library.h"
2526
#include "mathlib.h"
2627
#include "settings.h"
@@ -732,6 +733,75 @@ static void followVariableExpressionError(const Token *tok1, const Token *tok2,
732733
errors->push_back(item);
733734
}
734735

736+
const Token* followReferences(const Token* tok, ErrorPath* errors, int depth = 20)
737+
{
738+
if (!tok)
739+
return nullptr;
740+
if (depth < 0)
741+
return tok;
742+
const Variable *var = tok->variable();
743+
if (var && var->declarationId() == tok->varId()) {
744+
if (var->nameToken() == tok) {
745+
return tok;
746+
} else if (var->isReference() || var->isRValueReference()) {
747+
if (!var->declEndToken())
748+
return tok;
749+
if (var->isArgument()) {
750+
if (errors)
751+
errors->emplace_back(var->declEndToken(), "Passed to reference.");
752+
return tok;
753+
} else if (Token::simpleMatch(var->declEndToken(), "=")) {
754+
if (errors)
755+
errors->emplace_back(var->declEndToken(), "Assigned to reference.");
756+
const Token *vartok = var->declEndToken()->astOperand2();
757+
if (vartok == tok)
758+
return tok;
759+
if (vartok)
760+
return followReferences(vartok, errors, depth - 1);
761+
} else {
762+
return tok;
763+
}
764+
}
765+
} else if (Token::Match(tok->previous(), "%name% (")) {
766+
const Function *f = tok->previous()->function();
767+
if (f) {
768+
if (!Function::returnsReference(f))
769+
return tok;
770+
std::set<const Token*> result;
771+
ErrorPath errorPath;
772+
for (const Token* returnTok : Function::findReturns(f)) {
773+
if (returnTok == tok)
774+
continue;
775+
const Token* argvarTok = followReferences(returnTok, errors, depth - 1);
776+
const Variable* argvar = argvarTok->variable();
777+
if (!argvar)
778+
return tok;
779+
if (argvar->isArgument() && (argvar->isReference() || argvar->isRValueReference())) {
780+
int n = getArgumentPos(argvar, f);
781+
if (n < 0)
782+
return tok;
783+
std::vector<const Token*> args = getArguments(tok->previous());
784+
if (n >= args.size())
785+
return tok;
786+
const Token* argTok = args[n];
787+
ErrorPath er;
788+
er.emplace_back(returnTok, "Return reference.");
789+
er.emplace_back(tok->previous(), "Called function passing '" + argTok->expressionString() + "'.");
790+
const Token* tok2 = followReferences(argTok, &er, depth - 1);
791+
errorPath = er;
792+
result.insert(tok2);
793+
}
794+
}
795+
if (result.size() == 1) {
796+
if (errors)
797+
errors->insert(errors->end(), errorPath.begin(), errorPath.end());
798+
return *result.begin();
799+
}
800+
}
801+
}
802+
return tok;
803+
}
804+
735805
static bool isSameLifetime(const Token * const tok1, const Token * const tok2)
736806
{
737807
ValueFlow::Value v1 = getLifetimeObjValue(tok1);
@@ -851,6 +921,13 @@ bool isSameExpression(bool cpp, bool macro, const Token *tok1, const Token *tok2
851921
return isSameExpression(cpp, macro, varTok1, varTok2, library, true, followVar, errors);
852922
}
853923
}
924+
// Follow references
925+
if (tok1->str() != tok2->str()) {
926+
const Token* refTok1 = followReferences(tok1, errors);
927+
const Token* refTok2 = followReferences(tok2, errors);
928+
if (refTok1 != tok1 || refTok2 != tok2)
929+
return isSameExpression(cpp, macro, refTok1, refTok2, library, pure, followVar, errors);
930+
}
854931
if (tok1->varId() != tok2->varId() || tok1->str() != tok2->str() || tok1->originalName() != tok2->originalName()) {
855932
if ((Token::Match(tok1,"<|>") && Token::Match(tok2,"<|>")) ||
856933
(Token::Match(tok1,"<=|>=") && Token::Match(tok2,"<=|>="))) {

test/testother.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4000,6 +4000,12 @@ class TestOther : public TestFixture {
40004000
check("void f(int i) { i = !!i; }");
40014001
ASSERT_EQUALS("", errout.str());
40024002

4003+
check("void foo() {\n"
4004+
" int x = 1;\n"
4005+
" int &ref = x;\n"
4006+
" ref = x;\n"
4007+
"}\n");
4008+
ASSERT_EQUALS("[test.cpp:4]: (warning) Redundant assignment of 'ref' to itself.\n", errout.str());
40034009
}
40044010

40054011
void trac1132() {

0 commit comments

Comments
 (0)