diff --git a/lib/astutils.cpp b/lib/astutils.cpp index a4f948f9c..071d5159c 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -166,6 +166,21 @@ static bool isAliased(const Token * startTok, const Token * endTok, unsigned int return false; } +static bool exprDependsOnThis(const Token *expr) +{ + if (!expr) + return false; + // calling nonstatic method? + if (Token::Match(expr->previous(), "!!:: %name% (") && expr->function() && expr->function()->nestedIn && expr->function()->nestedIn->isClassOrStruct()) { + // is it a method of this? + const Scope *nestedIn = expr->scope(); + while (nestedIn && nestedIn != expr->function()->nestedIn) + nestedIn = nestedIn->nestedIn; + return nestedIn == expr->function()->nestedIn; + } + return exprDependsOnThis(expr->astOperand1()) || exprDependsOnThis(expr->astOperand2()); +} + /// This takes a token that refers to a variable and it will return the token /// to the expression that the variable is assigned to. If its not valid to /// make such substitution then it will return the original token. @@ -189,6 +204,9 @@ static const Token * followVariableExpression(const Token * tok, bool cpp, const const Token * varTok = getVariableInitExpression(var); if (!varTok) return tok; + // Bailout. If variable value depends on value of "this". + if (exprDependsOnThis(varTok)) + return tok; // Skip array access if (Token::simpleMatch(varTok, "[")) return tok; diff --git a/test/testcondition.cpp b/test/testcondition.cpp index 75b1f28b7..6bfc72bd6 100644 --- a/test/testcondition.cpp +++ b/test/testcondition.cpp @@ -88,6 +88,7 @@ private: TEST_CASE(oppositeInnerCondition3); TEST_CASE(oppositeInnerConditionAnd); TEST_CASE(oppositeInnerConditionEmpty); + TEST_CASE(oppositeInnerConditionFollowVar); TEST_CASE(identicalInnerCondition); @@ -2017,6 +2018,21 @@ private: ASSERT_EQUALS("", errout.str()); } + void oppositeInnerConditionFollowVar() { + check("struct X {\n" + " void f() {\n" + " const int flag = get();\n" + " if (flag) {\n" + " bar();\n" + " if (!get()) {}\n" + " }\n" + " }\n" + " void bar();\n" + " int get() const;\n" + "};"); + ASSERT_EQUALS("", errout.str()); + } + void identicalInnerCondition() { check("void f1(int a, int b) { if(a==b) if(a==b) {}}"); ASSERT_EQUALS("[test.cpp:1] -> [test.cpp:1]: (warning) Identical inner 'if' condition is always true.\n", errout.str());