Fix #3208 (Simplify pointer to standard type, C only)
The symbol database is unavailable during token simplification and &data[0] might return something completely different for C++. Moved code_is_c() from checkOther to Tokenizer.
This commit is contained in:
parent
1ec32e27db
commit
a52b73f9f9
|
@ -147,7 +147,7 @@ void CheckOther::clarifyCondition()
|
||||||
tok2 = tok2->link();
|
tok2 = tok2->link();
|
||||||
else if (Token::Match(tok2, "<|<=|==|!=|>|>=")) {
|
else if (Token::Match(tok2, "<|<=|==|!=|>|>=")) {
|
||||||
// This might be a template
|
// This might be a template
|
||||||
if (!code_is_c() && Token::Match(tok2->previous(), "%var% <"))
|
if (!_tokenizer->code_is_c() && Token::Match(tok2->previous(), "%var% <"))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
clarifyConditionError(tok, tok->strAt(2) == "=", false);
|
clarifyConditionError(tok, tok->strAt(2) == "=", false);
|
||||||
|
@ -1163,7 +1163,7 @@ void CheckOther::checkComparisonOfBoolWithInt()
|
||||||
std::map<unsigned int, bool>::const_iterator iVar = boolvars.find(varTok->varId());
|
std::map<unsigned int, bool>::const_iterator iVar = boolvars.find(varTok->varId());
|
||||||
if (iVar != boolvars.end() && iVar->second && // Variable has to be a boolean
|
if (iVar != boolvars.end() && iVar->second && // Variable has to be a boolean
|
||||||
((tok->tokAt(1)->str() != "==" && tok->tokAt(1)->str() != "!=") ||
|
((tok->tokAt(1)->str() != "==" && tok->tokAt(1)->str() != "!=") ||
|
||||||
((MathLib::toLongNumber(numTok->str()) != 0) && (!code_is_c() || MathLib::toLongNumber(numTok->str()) != 1)))) { // == 0 and != 0 are allowed, for C also == 1 and != 1
|
((MathLib::toLongNumber(numTok->str()) != 0) && (!_tokenizer->code_is_c() || MathLib::toLongNumber(numTok->str()) != 1)))) { // == 0 and != 0 are allowed, for C also == 1 and != 1
|
||||||
comparisonOfBoolWithIntError(varTok, numTok->str());
|
comparisonOfBoolWithIntError(varTok, numTok->str());
|
||||||
}
|
}
|
||||||
} else if (Token::Match(tok, "%num% >|>=|==|!=|<=|< %var%")) { // Comparing number with variable
|
} else if (Token::Match(tok, "%num% >|>=|==|!=|<=|< %var%")) { // Comparing number with variable
|
||||||
|
@ -1172,7 +1172,7 @@ void CheckOther::checkComparisonOfBoolWithInt()
|
||||||
std::map<unsigned int, bool>::const_iterator iVar = boolvars.find(varTok->varId());
|
std::map<unsigned int, bool>::const_iterator iVar = boolvars.find(varTok->varId());
|
||||||
if (iVar != boolvars.end() && iVar->second && // Variable has to be a boolean
|
if (iVar != boolvars.end() && iVar->second && // Variable has to be a boolean
|
||||||
((tok->tokAt(1)->str() != "==" && tok->tokAt(1)->str() != "!=") ||
|
((tok->tokAt(1)->str() != "==" && tok->tokAt(1)->str() != "!=") ||
|
||||||
((MathLib::toLongNumber(numTok->str()) != 0) && (!code_is_c() || MathLib::toLongNumber(numTok->str()) != 1)))) { // == 0 and != 0 are allowed, for C also == 1 and != 1
|
((MathLib::toLongNumber(numTok->str()) != 0) && (!_tokenizer->code_is_c() || MathLib::toLongNumber(numTok->str()) != 1)))) { // == 0 and != 0 are allowed, for C also == 1 and != 1
|
||||||
comparisonOfBoolWithIntError(varTok, numTok->str());
|
comparisonOfBoolWithIntError(varTok, numTok->str());
|
||||||
}
|
}
|
||||||
} else if (Token::Match(tok, "true|false >|>=|==|!=|<=|< %var%")) { // Comparing boolean constant with variable
|
} else if (Token::Match(tok, "true|false >|>=|==|!=|<=|< %var%")) { // Comparing boolean constant with variable
|
||||||
|
@ -1899,24 +1899,10 @@ static bool isFunction(const std::string &name, const Token *startToken)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CheckOther::code_is_c() const
|
|
||||||
{
|
|
||||||
const std::string fname = _tokenizer->getFiles()->at(0);
|
|
||||||
const size_t position = fname.rfind(".");
|
|
||||||
|
|
||||||
if (position != std::string::npos) {
|
|
||||||
const std::string ext = fname.substr(position);
|
|
||||||
if (ext == ".c" || ext == ".C")
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CheckOther::checkMisusedScopedObject()
|
void CheckOther::checkMisusedScopedObject()
|
||||||
{
|
{
|
||||||
// Skip this check for .c files
|
// Skip this check for .c files
|
||||||
if (code_is_c()) {
|
if (_tokenizer->code_is_c()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -398,8 +398,6 @@ private:
|
||||||
|
|
||||||
return varname;
|
return varname;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool code_is_c() const;
|
|
||||||
};
|
};
|
||||||
/// @}
|
/// @}
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
|
@ -2338,6 +2338,9 @@ bool Tokenizer::tokenize(std::istream &code,
|
||||||
// operator = => operator=
|
// operator = => operator=
|
||||||
simplifyOperatorName();
|
simplifyOperatorName();
|
||||||
|
|
||||||
|
// Simplify pointer to standard types (C only)
|
||||||
|
simplifyPointerToStandardType();
|
||||||
|
|
||||||
// simplify function pointers
|
// simplify function pointers
|
||||||
simplifyFunctionPointers();
|
simplifyFunctionPointers();
|
||||||
|
|
||||||
|
@ -5390,6 +5393,22 @@ void Tokenizer::simplifyFunctionParameters()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Tokenizer::simplifyPointerToStandardType()
|
||||||
|
{
|
||||||
|
if (!code_is_c())
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (Token *tok = _tokens; tok; tok = tok->next()) {
|
||||||
|
if (!Token::Match(tok, "& %var% [ 0 ]"))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Remove '[ 0 ]' suffix
|
||||||
|
tok->next()->eraseTokens(tok->next(), tok->tokAt(5));
|
||||||
|
// Remove '&' prefix
|
||||||
|
tok = tok->previous();
|
||||||
|
tok->deleteNext();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Tokenizer:: simplifyFunctionPointers()
|
void Tokenizer:: simplifyFunctionPointers()
|
||||||
{
|
{
|
||||||
|
@ -9599,3 +9618,17 @@ void Tokenizer::printUnknownTypes()
|
||||||
_errorLogger->reportOut(ss.str());
|
_errorLogger->reportOut(ss.str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Tokenizer::code_is_c() const
|
||||||
|
{
|
||||||
|
const std::string fname = getFiles()->at(0);
|
||||||
|
const size_t position = fname.rfind(".");
|
||||||
|
|
||||||
|
if (position != std::string::npos) {
|
||||||
|
const std::string ext = fname.substr(position);
|
||||||
|
if (ext == ".c" || ext == ".C")
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
|
@ -514,6 +514,9 @@ public:
|
||||||
*/
|
*/
|
||||||
void simplifyStd();
|
void simplifyStd();
|
||||||
|
|
||||||
|
/** Simplify pointer to standard type (C only) */
|
||||||
|
void simplifyPointerToStandardType();
|
||||||
|
|
||||||
/** Simplify function pointers */
|
/** Simplify function pointers */
|
||||||
void simplifyFunctionPointers();
|
void simplifyFunctionPointers();
|
||||||
|
|
||||||
|
@ -711,6 +714,9 @@ public:
|
||||||
*/
|
*/
|
||||||
void printUnknownTypes();
|
void printUnknownTypes();
|
||||||
|
|
||||||
|
/** Checks if the file extensions is .c or .C */
|
||||||
|
bool code_is_c() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/** Disable copy constructor, no implementation */
|
/** Disable copy constructor, no implementation */
|
||||||
Tokenizer(const Tokenizer &);
|
Tokenizer(const Tokenizer &);
|
||||||
|
|
|
@ -35,7 +35,7 @@ private:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void check(const char code[], bool experimental = true) {
|
void check(const char code[], bool experimental = true, const std::string &filename="test.cpp") {
|
||||||
// Clear the error buffer..
|
// Clear the error buffer..
|
||||||
errout.str("");
|
errout.str("");
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ private:
|
||||||
// Tokenize..
|
// Tokenize..
|
||||||
Tokenizer tokenizer(&settings, this);
|
Tokenizer tokenizer(&settings, this);
|
||||||
std::istringstream istr(code);
|
std::istringstream istr(code);
|
||||||
tokenizer.tokenize(istr, "test.cpp");
|
tokenizer.tokenize(istr, filename.c_str());
|
||||||
|
|
||||||
// Assign variable ids
|
// Assign variable ids
|
||||||
tokenizer.simplifyTokenList();
|
tokenizer.simplifyTokenList();
|
||||||
|
@ -3436,6 +3436,15 @@ private:
|
||||||
"}\n");
|
"}\n");
|
||||||
ASSERT_EQUALS("[test.cpp:4]: (warning) The buffer 'buf' is not zero-terminated after the call to readlink().\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:4]: (warning) The buffer 'buf' is not zero-terminated after the call to readlink().\n", errout.str());
|
||||||
|
|
||||||
|
// C only: Primitive pointer simplification
|
||||||
|
check("void f()\n"
|
||||||
|
"{\n"
|
||||||
|
" char buf[255];\n"
|
||||||
|
" ssize_t len = readlink(path, &buf[0], sizeof(buf)-1);\n"
|
||||||
|
" printf(\"%s\n\", buf);\n"
|
||||||
|
"}\n", true, "test.c");
|
||||||
|
ASSERT_EQUALS("[test.c:4]: (warning) The buffer 'buf' is not zero-terminated after the call to readlink().\n", errout.str());
|
||||||
|
|
||||||
check("void f()\n"
|
check("void f()\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" char buf[255];\n"
|
" char buf[255];\n"
|
||||||
|
|
|
@ -286,6 +286,7 @@ private:
|
||||||
TEST_CASE(simplifyConst);
|
TEST_CASE(simplifyConst);
|
||||||
TEST_CASE(switchCase);
|
TEST_CASE(switchCase);
|
||||||
|
|
||||||
|
TEST_CASE(simplifyPointerToStandardType);
|
||||||
TEST_CASE(functionpointer1);
|
TEST_CASE(functionpointer1);
|
||||||
TEST_CASE(functionpointer2);
|
TEST_CASE(functionpointer2);
|
||||||
TEST_CASE(functionpointer3);
|
TEST_CASE(functionpointer3);
|
||||||
|
@ -375,7 +376,7 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::string tokenizeAndStringify(const char code[], bool simplify = false, bool expand = true, Settings::PlatformType platform = Settings::Unspecified) {
|
std::string tokenizeAndStringify(const char code[], bool simplify = false, bool expand = true, Settings::PlatformType platform = Settings::Unspecified, const std::string &filename="test.cpp") {
|
||||||
errout.str("");
|
errout.str("");
|
||||||
|
|
||||||
Settings settings;
|
Settings settings;
|
||||||
|
@ -385,7 +386,7 @@ private:
|
||||||
// tokenize..
|
// tokenize..
|
||||||
Tokenizer tokenizer(&settings, this);
|
Tokenizer tokenizer(&settings, this);
|
||||||
std::istringstream istr(code);
|
std::istringstream istr(code);
|
||||||
tokenizer.tokenize(istr, "test.cpp");
|
tokenizer.tokenize(istr, filename.c_str());
|
||||||
if (simplify)
|
if (simplify)
|
||||||
tokenizer.simplifyTokenList();
|
tokenizer.simplifyTokenList();
|
||||||
|
|
||||||
|
@ -4669,6 +4670,21 @@ private:
|
||||||
tokenizeAndStringify("void foo (int i) { switch(i) { case -1: break; } }"));
|
tokenizeAndStringify("void foo (int i) { switch(i) { case -1: break; } }"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void simplifyPointerToStandardType() {
|
||||||
|
// Pointer to standard type
|
||||||
|
ASSERT_EQUALS("char buf [ 100 ] ; readlink ( path , buf , 99 ) ;",
|
||||||
|
tokenizeAndStringify("char buf[100] ; readlink(path, &buf[0], 99);",
|
||||||
|
false, true, Settings::Unspecified, "test.c"));
|
||||||
|
|
||||||
|
// Simplification of unknown type - C only
|
||||||
|
ASSERT_EQUALS("foo data [ 100 ] ; something ( foo ) ;",
|
||||||
|
tokenizeAndStringify("foo data[100]; something(&foo[0]);", false, true, Settings::Unspecified, "test.c"));
|
||||||
|
|
||||||
|
// C++: No pointer simplification
|
||||||
|
ASSERT_EQUALS("foo data [ 100 ] ; something ( & foo [ 0 ] ) ;",
|
||||||
|
tokenizeAndStringify("foo data[100]; something(&foo[0]);"));
|
||||||
|
}
|
||||||
|
|
||||||
std::string simplifyFunctionPointers(const char code[]) {
|
std::string simplifyFunctionPointers(const char code[]) {
|
||||||
errout.str("");
|
errout.str("");
|
||||||
Settings settings;
|
Settings settings;
|
||||||
|
|
Loading…
Reference in New Issue