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:
Thomas Jarosch 2011-10-16 08:09:57 +02:00 committed by Daniel Marjamäki
parent 1ec32e27db
commit a52b73f9f9
6 changed files with 72 additions and 24 deletions

View File

@ -147,7 +147,7 @@ void CheckOther::clarifyCondition()
tok2 = tok2->link();
else if (Token::Match(tok2, "<|<=|==|!=|>|>=")) {
// 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;
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());
if (iVar != boolvars.end() && iVar->second && // Variable has to be a boolean
((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());
}
} 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());
if (iVar != boolvars.end() && iVar->second && // Variable has to be a boolean
((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());
}
} 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;
}
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()
{
// Skip this check for .c files
if (code_is_c()) {
if (_tokenizer->code_is_c()) {
return;
}

View File

@ -398,8 +398,6 @@ private:
return varname;
}
bool code_is_c() const;
};
/// @}
//---------------------------------------------------------------------------

View File

@ -2338,6 +2338,9 @@ bool Tokenizer::tokenize(std::istream &code,
// operator = => operator=
simplifyOperatorName();
// Simplify pointer to standard types (C only)
simplifyPointerToStandardType();
// simplify function pointers
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()
{
@ -9599,3 +9618,17 @@ void Tokenizer::printUnknownTypes()
_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;
}

View File

@ -514,6 +514,9 @@ public:
*/
void simplifyStd();
/** Simplify pointer to standard type (C only) */
void simplifyPointerToStandardType();
/** Simplify function pointers */
void simplifyFunctionPointers();
@ -711,6 +714,9 @@ public:
*/
void printUnknownTypes();
/** Checks if the file extensions is .c or .C */
bool code_is_c() const;
private:
/** Disable copy constructor, no implementation */
Tokenizer(const Tokenizer &);

View File

@ -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..
errout.str("");
@ -49,7 +49,7 @@ private:
// Tokenize..
Tokenizer tokenizer(&settings, this);
std::istringstream istr(code);
tokenizer.tokenize(istr, "test.cpp");
tokenizer.tokenize(istr, filename.c_str());
// Assign variable ids
tokenizer.simplifyTokenList();
@ -3436,6 +3436,15 @@ private:
"}\n");
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"
"{\n"
" char buf[255];\n"

View File

@ -286,6 +286,7 @@ private:
TEST_CASE(simplifyConst);
TEST_CASE(switchCase);
TEST_CASE(simplifyPointerToStandardType);
TEST_CASE(functionpointer1);
TEST_CASE(functionpointer2);
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("");
Settings settings;
@ -385,7 +386,7 @@ private:
// tokenize..
Tokenizer tokenizer(&settings, this);
std::istringstream istr(code);
tokenizer.tokenize(istr, "test.cpp");
tokenizer.tokenize(istr, filename.c_str());
if (simplify)
tokenizer.simplifyTokenList();
@ -4669,6 +4670,21 @@ private:
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[]) {
errout.str("");
Settings settings;