Tokenizer: Added new function isFunctionParameterPassedByValue that check if a parameter is passed by value
This commit is contained in:
parent
8c39b95aae
commit
8af044255d
|
@ -6089,6 +6089,15 @@ bool Tokenizer::simplifyKnownVariablesSimplify(Token **tok2, Token *tok3, unsign
|
||||||
ret = true;
|
ret = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// parameter in function call..
|
||||||
|
if (tok3->varId() == varid && Token::Match(tok3->previous(), "[(,] %var% [,)]")) {
|
||||||
|
// If the parameter is passed by value then simplify it
|
||||||
|
if (isFunctionParameterPassedByValue(tok3)) {
|
||||||
|
tok3->str(value);
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Variable is used somehow in a non-defined pattern => bail out
|
// Variable is used somehow in a non-defined pattern => bail out
|
||||||
if (tok3->varId() == varid) {
|
if (tok3->varId() == varid) {
|
||||||
// This is a really generic bailout so let's try to avoid this.
|
// This is a really generic bailout so let's try to avoid this.
|
||||||
|
@ -7298,6 +7307,73 @@ const Token *Tokenizer::getFunctionTokenByName(const char funcname[]) const
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Tokenizer::isFunctionParameterPassedByValue(const Token *fpar) const
|
||||||
|
{
|
||||||
|
// TODO: If symbol database is available, use it.
|
||||||
|
const Token *ftok;
|
||||||
|
|
||||||
|
// Look at function call, what parameter number is it?
|
||||||
|
unsigned int paranthesis = 1;
|
||||||
|
unsigned int parameter = 1;
|
||||||
|
for (ftok = fpar; ftok; ftok = ftok->previous()) {
|
||||||
|
if (ftok->str() == "(") {
|
||||||
|
--paranthesis;
|
||||||
|
if (paranthesis == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (ftok->str() == ")") {
|
||||||
|
++paranthesis;
|
||||||
|
} else if (paranthesis == 1 && ftok->str() == ",") {
|
||||||
|
++parameter;
|
||||||
|
} else if (Token::Match(ftok, "[;{}]")) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is this a function call?
|
||||||
|
if (ftok && Token::Match(ftok->tokAt(-2), "[;{}=] %var% (")) {
|
||||||
|
const std::string functionName(ftok->previous()->str() + " (");
|
||||||
|
|
||||||
|
// Locate function declaration..
|
||||||
|
unsigned int indentlevel = 0;
|
||||||
|
for (const Token *tok = tokens(); tok; tok = tok->next()) {
|
||||||
|
if (tok->str() == "{")
|
||||||
|
++indentlevel;
|
||||||
|
else if (tok->str() == "}")
|
||||||
|
indentlevel = (indentlevel > 0) ? indentlevel - 1U : 0U;
|
||||||
|
else if (indentlevel == 0 && tok->isName() && Token::simpleMatch(tok, functionName.c_str())) {
|
||||||
|
// Goto parameter
|
||||||
|
tok = tok->tokAt(2);
|
||||||
|
unsigned int par = 1;
|
||||||
|
while (tok && par < parameter) {
|
||||||
|
if (tok->str() == ")")
|
||||||
|
break;
|
||||||
|
if (tok->str() == ",")
|
||||||
|
++par;
|
||||||
|
tok = tok->next();
|
||||||
|
}
|
||||||
|
if (!tok)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// If parameter was found, determine if it's passed by value
|
||||||
|
if (par == parameter) {
|
||||||
|
bool knowntype = false;
|
||||||
|
while (tok && tok->isName()) {
|
||||||
|
knowntype |= tok->isStandardType();
|
||||||
|
knowntype |= (tok->str() == "struct");
|
||||||
|
tok = tok->next();
|
||||||
|
}
|
||||||
|
if (!tok || !knowntype)
|
||||||
|
return false;
|
||||||
|
if (tok->str() != "," && tok->str() != ")")
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
|
@ -160,6 +160,14 @@ public:
|
||||||
*/
|
*/
|
||||||
const Token *getFunctionTokenByName(const char funcname[]) const;
|
const Token *getFunctionTokenByName(const char funcname[]) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try to determine if function parameter is passed by value by looking
|
||||||
|
* at the function declaration.
|
||||||
|
* @param fpar token for function parameter in the function call
|
||||||
|
* @return true if the parameter is passed by value. if unsure, false is returned
|
||||||
|
*/
|
||||||
|
bool isFunctionParameterPassedByValue(const Token *fpar) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get error messages that the tokenizer generate
|
* get error messages that the tokenizer generate
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -168,6 +168,7 @@ private:
|
||||||
TEST_CASE(simplifyKnownVariablesBailOutSwitchBreak); // ticket #2324
|
TEST_CASE(simplifyKnownVariablesBailOutSwitchBreak); // ticket #2324
|
||||||
TEST_CASE(simplifyKnownVariablesFloat); // #2454 - float variable
|
TEST_CASE(simplifyKnownVariablesFloat); // #2454 - float variable
|
||||||
TEST_CASE(simplifyKnownVariablesClassMember); // #2815 - value of class member may be changed by function call
|
TEST_CASE(simplifyKnownVariablesClassMember); // #2815 - value of class member may be changed by function call
|
||||||
|
TEST_CASE(simplifyKnownVariablesFunctionCalls); // Function calls (don't assume pass by reference)
|
||||||
TEST_CASE(simplifyExternC);
|
TEST_CASE(simplifyExternC);
|
||||||
|
|
||||||
TEST_CASE(varid1);
|
TEST_CASE(varid1);
|
||||||
|
@ -2515,6 +2516,28 @@ private:
|
||||||
ASSERT_EQUALS(expected, tokenizeAndStringify(code,true));
|
ASSERT_EQUALS(expected, tokenizeAndStringify(code,true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void simplifyKnownVariablesFunctionCalls() {
|
||||||
|
{
|
||||||
|
const char code[] = "void a(int x);" // <- x is passed by value
|
||||||
|
"void b() {"
|
||||||
|
" int x = 123;"
|
||||||
|
" a(x);" // <- replace with a(123);
|
||||||
|
"}";
|
||||||
|
const char expected[] = "void a ( int x ) ; void b ( ) { a ( 123 ) ; }";
|
||||||
|
ASSERT_EQUALS(expected, tokenizeAndStringify(code,true));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const char code[] = "void a(int &x);" // <- x is passed by reference
|
||||||
|
"void b() {"
|
||||||
|
" int x = 123;"
|
||||||
|
" a(x);" // <- don't replace with a(123);
|
||||||
|
"}";
|
||||||
|
const char expected[] = "void a ( int & x ) ; void b ( ) { int x ; x = 123 ; a ( x ) ; }";
|
||||||
|
ASSERT_EQUALS(expected, tokenizeAndStringify(code,true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void simplifyKnownVariablesClassMember() {
|
void simplifyKnownVariablesClassMember() {
|
||||||
// Ticket #2815
|
// Ticket #2815
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue