Fixed #1388 (enum token/template parameter confusion - False positive)
This commit is contained in:
parent
e44f0b1b8d
commit
f15c408f13
132
lib/tokenize.cpp
132
lib/tokenize.cpp
|
@ -5042,6 +5042,111 @@ void Tokenizer::simplifyNestedStrcat()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Tokenizer::duplicateEnumError(const Token * tok1, const Token * tok2, const std::string & type)
|
||||||
|
{
|
||||||
|
if (!(_settings && _settings->_checkCodingStyle))
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::list<ErrorLogger::ErrorMessage::FileLocation> locationList;
|
||||||
|
ErrorLogger::ErrorMessage::FileLocation loc;
|
||||||
|
loc.line = tok1->linenr();
|
||||||
|
loc.file = file(tok1);
|
||||||
|
locationList.push_back(loc);
|
||||||
|
loc.line = tok2->linenr();
|
||||||
|
loc.file = file(tok2);
|
||||||
|
locationList.push_back(loc);
|
||||||
|
|
||||||
|
const ErrorLogger::ErrorMessage errmsg(locationList,
|
||||||
|
"style",
|
||||||
|
std::string(type + " '" + tok2->str() +
|
||||||
|
"' hides enumerator of same name"),
|
||||||
|
"variableHidingEnum");
|
||||||
|
|
||||||
|
if (_errorLogger)
|
||||||
|
_errorLogger->reportErr(errmsg);
|
||||||
|
else
|
||||||
|
Check::reportError(errmsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if this statement is a duplicate definition. A duplicate
|
||||||
|
// definition will hide the enumerator within it's scope so just
|
||||||
|
// skip the entire scope of the duplicate.
|
||||||
|
bool Tokenizer::duplicateDefinition(Token ** tokPtr, const Token * name)
|
||||||
|
{
|
||||||
|
// check for an end of definition
|
||||||
|
const Token * tok = *tokPtr;
|
||||||
|
if (tok && tok->next() && Token::Match(tok->next(), ";|,|[|=|)|>"))
|
||||||
|
{
|
||||||
|
const Token * end = tok->next();
|
||||||
|
|
||||||
|
if (end->str() == "[")
|
||||||
|
{
|
||||||
|
end = end->link()->next();
|
||||||
|
}
|
||||||
|
else if (end->str() == ",")
|
||||||
|
{
|
||||||
|
// find end of definition
|
||||||
|
int level = 0;
|
||||||
|
while (end && end->next() && (!Token::Match(end->next(), ";|)|>") ||
|
||||||
|
(end->next()->str() == ")" && level == 0)))
|
||||||
|
{
|
||||||
|
if (end->next()->str() == "(")
|
||||||
|
level++;
|
||||||
|
else if (end->next()->str() == ")")
|
||||||
|
level--;
|
||||||
|
|
||||||
|
end = end->next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (end)
|
||||||
|
{
|
||||||
|
if (Token::Match(end, ") {")) // function parameter ?
|
||||||
|
{
|
||||||
|
// look backwards
|
||||||
|
if (tok->previous()->str() == "enum" ||
|
||||||
|
(Token::Match(tok->previous(), "%type%") &&
|
||||||
|
tok->previous()->str() != "return"))
|
||||||
|
{
|
||||||
|
duplicateEnumError(*tokPtr, name, "Function parameter");
|
||||||
|
// duplicate definition so skip entire function
|
||||||
|
*tokPtr = end->next()->link();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (end->str() == ">") // template parameter ?
|
||||||
|
{
|
||||||
|
// look backwards
|
||||||
|
if (tok->previous()->str() == "enum" ||
|
||||||
|
(Token::Match(tok->previous(), "%type%") &&
|
||||||
|
tok->previous()->str() != "return"))
|
||||||
|
{
|
||||||
|
// duplicate definition so skip entire template
|
||||||
|
while (end && end->str() != "{")
|
||||||
|
end = end->next();
|
||||||
|
if (end)
|
||||||
|
{
|
||||||
|
duplicateEnumError(*tokPtr, name, "Template parameter");
|
||||||
|
*tokPtr = end->link();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// look backwards
|
||||||
|
if (tok->previous()->str() == "enum" ||
|
||||||
|
(Token::Match(tok->previous(), "%type%") &&
|
||||||
|
tok->previous()->str() != "return"))
|
||||||
|
{
|
||||||
|
duplicateEnumError(*tokPtr, name, "Variable");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void Tokenizer::simplifyEnum()
|
void Tokenizer::simplifyEnum()
|
||||||
{
|
{
|
||||||
|
@ -5090,6 +5195,9 @@ void Tokenizer::simplifyEnum()
|
||||||
Token * lastEnumValueStart = 0;
|
Token * lastEnumValueStart = 0;
|
||||||
Token * lastEnumValueEnd = 0;
|
Token * lastEnumValueEnd = 0;
|
||||||
|
|
||||||
|
// iterate over all enumerators between { and }
|
||||||
|
// Give each enumerator the const value specified or if not specified, 1 + the
|
||||||
|
// previous value or 0 if it is the first one.
|
||||||
for (; tok1 && tok1 != end; tok1 = tok1->next())
|
for (; tok1 && tok1 != end; tok1 = tok1->next())
|
||||||
{
|
{
|
||||||
Token * enumName = 0;
|
Token * enumName = 0;
|
||||||
|
@ -5099,6 +5207,7 @@ void Tokenizer::simplifyEnum()
|
||||||
|
|
||||||
if (Token::Match(tok1->previous(), ",|{ %type% ,|}"))
|
if (Token::Match(tok1->previous(), ",|{ %type% ,|}"))
|
||||||
{
|
{
|
||||||
|
// no value specified
|
||||||
enumName = tok1;
|
enumName = tok1;
|
||||||
lastValue++;
|
lastValue++;
|
||||||
tok1->insertToken("=");
|
tok1->insertToken("=");
|
||||||
|
@ -5106,11 +5215,12 @@ void Tokenizer::simplifyEnum()
|
||||||
|
|
||||||
if (lastEnumValueStart && lastEnumValueEnd)
|
if (lastEnumValueStart && lastEnumValueEnd)
|
||||||
{
|
{
|
||||||
|
// previous value was an expression
|
||||||
Token * valueStart = tok1;
|
Token * valueStart = tok1;
|
||||||
std::stack<Token *> links;
|
std::stack<Token *> links;
|
||||||
for (Token *tok2 = lastEnumValueStart; tok2 != lastEnumValueEnd->next(); tok2 = tok2->next())
|
for (Token *tok2 = lastEnumValueStart; tok2 != lastEnumValueEnd->next(); tok2 = tok2->next())
|
||||||
{
|
{
|
||||||
tok1->insertToken(tok2->strAt(0));
|
tok1->insertToken(tok2->str());
|
||||||
tok1 = tok1->next();
|
tok1 = tok1->next();
|
||||||
|
|
||||||
// Check for links and fix them up
|
// Check for links and fix them up
|
||||||
|
@ -5127,21 +5237,24 @@ void Tokenizer::simplifyEnum()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// value is previous expression + 1
|
||||||
tok1->insertToken("+");
|
tok1->insertToken("+");
|
||||||
tok1 = tok1->next();
|
tok1 = tok1->next();
|
||||||
tok1->insertToken(MathLib::toString<long>(lastValue).c_str());
|
tok1->insertToken(MathLib::toString<long>(lastValue));
|
||||||
enumValue = 0;
|
enumValue = 0;
|
||||||
enumValueStart = valueStart->next();
|
enumValueStart = valueStart->next();
|
||||||
enumValueEnd = tok1->next();
|
enumValueEnd = tok1->next();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// value is previous numeric value + 1
|
||||||
tok1->insertToken(MathLib::toString<long>(lastValue));
|
tok1->insertToken(MathLib::toString<long>(lastValue));
|
||||||
enumValue = tok1->next();
|
enumValue = tok1->next();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (Token::Match(tok1->previous(), ",|{ %type% = %num% ,|}"))
|
else if (Token::Match(tok1->previous(), ",|{ %type% = %num% ,|}"))
|
||||||
{
|
{
|
||||||
|
// value is specified numeric value
|
||||||
enumName = tok1;
|
enumName = tok1;
|
||||||
lastValue = MathLib::toLongNumber(tok1->strAt(2));
|
lastValue = MathLib::toLongNumber(tok1->strAt(2));
|
||||||
enumValue = tok1->tokAt(2);
|
enumValue = tok1->tokAt(2);
|
||||||
|
@ -5150,6 +5263,7 @@ void Tokenizer::simplifyEnum()
|
||||||
}
|
}
|
||||||
else if (Token::Match(tok1->previous(), ",|{ %type% = "))
|
else if (Token::Match(tok1->previous(), ",|{ %type% = "))
|
||||||
{
|
{
|
||||||
|
// value is specified expression
|
||||||
enumName = tok1;
|
enumName = tok1;
|
||||||
lastValue = 0;
|
lastValue = 0;
|
||||||
tok1 = tok1->tokAt(2);
|
tok1 = tok1->tokAt(2);
|
||||||
|
@ -5166,11 +5280,14 @@ void Tokenizer::simplifyEnum()
|
||||||
|
|
||||||
enumValueEnd = enumValueEnd->next();
|
enumValueEnd = enumValueEnd->next();
|
||||||
}
|
}
|
||||||
|
// remember this expression in case it needs to be incremented
|
||||||
lastEnumValueStart = enumValueStart;
|
lastEnumValueStart = enumValueStart;
|
||||||
lastEnumValueEnd = enumValueEnd;
|
lastEnumValueEnd = enumValueEnd;
|
||||||
|
// skip over expression
|
||||||
tok1 = enumValueEnd;
|
tok1 = enumValueEnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// find all uses of this enumerator and substitute it's value for it's name
|
||||||
if (enumName && (enumValue || (enumValueStart && enumValueEnd)))
|
if (enumName && (enumValue || (enumValueStart && enumValueEnd)))
|
||||||
{
|
{
|
||||||
const std::string pattern(className.empty() ? "" : (className + " :: " + enumName->str()).c_str());
|
const std::string pattern(className.empty() ? "" : (className + " :: " + enumName->str()).c_str());
|
||||||
|
@ -5196,7 +5313,9 @@ void Tokenizer::simplifyEnum()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (tok2->str() == "{")
|
else if (tok2->str() == "{")
|
||||||
|
{
|
||||||
++level;
|
++level;
|
||||||
|
}
|
||||||
else if (!pattern.empty() && Token::Match(tok2, pattern.c_str()))
|
else if (!pattern.empty() && Token::Match(tok2, pattern.c_str()))
|
||||||
{
|
{
|
||||||
simplifyEnum = true;
|
simplifyEnum = true;
|
||||||
|
@ -5208,11 +5327,16 @@ void Tokenizer::simplifyEnum()
|
||||||
{
|
{
|
||||||
// Don't replace this enum if it's preceded by "::"
|
// Don't replace this enum if it's preceded by "::"
|
||||||
}
|
}
|
||||||
else
|
else if (!duplicateDefinition(&tok2, enumName))
|
||||||
{
|
{
|
||||||
simplifyEnum = true;
|
simplifyEnum = true;
|
||||||
hasClass = false;
|
hasClass = false;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// something with the same name.
|
||||||
|
exitScope = level;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (simplifyEnum)
|
if (simplifyEnum)
|
||||||
|
@ -5228,7 +5352,7 @@ void Tokenizer::simplifyEnum()
|
||||||
Token * nextToken = enumValueStart->next();
|
Token * nextToken = enumValueStart->next();
|
||||||
for (; nextToken != enumValueEnd->next(); nextToken = nextToken->next())
|
for (; nextToken != enumValueEnd->next(); nextToken = nextToken->next())
|
||||||
{
|
{
|
||||||
tok2->insertToken(nextToken->strAt(0));
|
tok2->insertToken(nextToken->str());
|
||||||
tok2 = tok2->next();
|
tok2 = tok2->next();
|
||||||
|
|
||||||
// Check for links and fix them up
|
// Check for links and fix them up
|
||||||
|
|
|
@ -414,6 +414,16 @@ private:
|
||||||
*/
|
*/
|
||||||
static std::string getNameForFunctionParams(const Token *start);
|
static std::string getNameForFunctionParams(const Token *start);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check for duplicate enum definition
|
||||||
|
*/
|
||||||
|
bool duplicateDefinition(Token **tokPtr, const Token *name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* duplicate enum definition error
|
||||||
|
*/
|
||||||
|
void duplicateEnumError(const Token *tok1, const Token *tok2, const std::string & type);
|
||||||
|
|
||||||
/** Disable assignment operator */
|
/** Disable assignment operator */
|
||||||
Tokenizer &operator=(const Tokenizer &);
|
Tokenizer &operator=(const Tokenizer &);
|
||||||
|
|
||||||
|
|
|
@ -189,6 +189,8 @@ private:
|
||||||
TEST_CASE(enum4);
|
TEST_CASE(enum4);
|
||||||
TEST_CASE(enum5);
|
TEST_CASE(enum5);
|
||||||
TEST_CASE(enum6);
|
TEST_CASE(enum6);
|
||||||
|
TEST_CASE(enum7);
|
||||||
|
TEST_CASE(enum8);
|
||||||
|
|
||||||
// remove "std::" on some standard functions
|
// remove "std::" on some standard functions
|
||||||
TEST_CASE(removestd);
|
TEST_CASE(removestd);
|
||||||
|
@ -3511,6 +3513,89 @@ private:
|
||||||
ASSERT_EQUALS(expected, tok(code, false));
|
ASSERT_EQUALS(expected, tok(code, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void enum7()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
// ticket 1388
|
||||||
|
const char code[] = "enum FOO {A,B,C};\n"
|
||||||
|
"int main()\n"
|
||||||
|
"{\n"
|
||||||
|
" int A = B;\n"
|
||||||
|
" { float A = C; }\n"
|
||||||
|
"}";
|
||||||
|
const char expected[] = "; "
|
||||||
|
"int main ( ) "
|
||||||
|
"{ "
|
||||||
|
"int A ; A = 1 ; "
|
||||||
|
"{ float A ; A = 2 ; } "
|
||||||
|
"}";
|
||||||
|
ASSERT_EQUALS(expected, tok(code, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const char code[] = "enum FOO {A,B,C};\n"
|
||||||
|
"void f(int A, float B, char C) { }";
|
||||||
|
const char expected[] = "; "
|
||||||
|
"void f ( int A , float B , char C ) { }";
|
||||||
|
ASSERT_EQUALS(expected, tok(code, false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check simplifyEnum
|
||||||
|
void checkSimplifyEnum(const char code[])
|
||||||
|
{
|
||||||
|
// Tokenize..
|
||||||
|
Settings settings;
|
||||||
|
settings._showAll = true;
|
||||||
|
settings._checkCodingStyle = true;
|
||||||
|
Tokenizer tokenizer(&settings, this);
|
||||||
|
std::istringstream istr(code);
|
||||||
|
errout.str("");
|
||||||
|
tokenizer.tokenize(istr, "test.cpp");
|
||||||
|
}
|
||||||
|
|
||||||
|
void enum8()
|
||||||
|
{
|
||||||
|
// ticket 1388
|
||||||
|
checkSimplifyEnum("enum Direction {N=100,E,S,W,ALL};\n"
|
||||||
|
"template<class T,int S> class EF_Vector{\n"
|
||||||
|
" T v_v[S];\n"
|
||||||
|
"\n"
|
||||||
|
"public:\n"
|
||||||
|
" EF_Vector();\n"
|
||||||
|
" explicit EF_Vector(const T &);\n"
|
||||||
|
" explicit EF_Vector(const T arr[S]);\n"
|
||||||
|
"};\n"
|
||||||
|
"\n"
|
||||||
|
"template<class T,int S>\n"
|
||||||
|
"EF_Vector<T,S>::EF_Vector()\n"
|
||||||
|
"{\n"
|
||||||
|
"}\n"
|
||||||
|
"\n"
|
||||||
|
"template<class T,int S>\n"
|
||||||
|
"EF_Vector<T,S>::EF_Vector(const T &t)\n"
|
||||||
|
"{\n"
|
||||||
|
" for(int i=0;i<S;i++)\n"
|
||||||
|
" v_v[i]=t;\n"
|
||||||
|
"}\n"
|
||||||
|
"\n"
|
||||||
|
"template<class T,int S>\n"
|
||||||
|
"EF_Vector<T,S>::EF_Vector(const T arr[S])\n"
|
||||||
|
"{\n"
|
||||||
|
" for(int i=0;i<S;i++)\n"
|
||||||
|
" v_v[i]=arr[i];\n"
|
||||||
|
"}\n"
|
||||||
|
"\n"
|
||||||
|
"void initialize()\n"
|
||||||
|
"{\n"
|
||||||
|
" EF_Vector<float,6> d;\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:1]: (style) Template parameter 'S' hides enumerator of same name\n"
|
||||||
|
"[test.cpp:11] -> [test.cpp:1]: (style) Template parameter 'S' hides enumerator of same name\n"
|
||||||
|
"[test.cpp:16] -> [test.cpp:1]: (style) Template parameter 'S' hides enumerator of same name\n"
|
||||||
|
"[test.cpp:23] -> [test.cpp:1]: (style) Template parameter 'S' hides enumerator of same name\n", errout.str());
|
||||||
|
}
|
||||||
|
|
||||||
void removestd()
|
void removestd()
|
||||||
{
|
{
|
||||||
ASSERT_EQUALS("; strcpy ( a , b ) ;", tok("; std::strcpy(a,b);"));
|
ASSERT_EQUALS("; strcpy ( a , b ) ;", tok("; std::strcpy(a,b);"));
|
||||||
|
|
Loading…
Reference in New Issue