This commit is contained in:
Sébastien Debrard 2011-03-03 21:35:32 +01:00
commit a69fbffa76
9 changed files with 319 additions and 162 deletions

View File

@ -266,7 +266,6 @@ void CheckAutoVariables::returnPointerToLocalArray()
tok2 = tok2->next()->link();
unsigned int indentlevel = 0;
std::set<unsigned int> arrayVar;
for (; tok2; tok2 = tok2->next())
{
// indentlevel..
@ -279,21 +278,13 @@ void CheckAutoVariables::returnPointerToLocalArray()
--indentlevel;
}
// Declaring a local array..
if (Token::Match(tok2, "[;{}] %type% %var% ["))
{
const unsigned int varid = tok2->tokAt(2)->varId();
if (varid > 0)
{
arrayVar.insert(varid);
}
}
// Return pointer to local array variable..
if (Token::Match(tok2, "return %var% ;"))
{
const unsigned int varid = tok2->next()->varId();
if (varid > 0 && arrayVar.find(varid) != arrayVar.end())
const Variable *var = symbolDatabase->getVariableFromVarId(varid);
if (var && var->isLocal() && !var->isStatic() && var->isArray())
{
errorReturnPointerToLocalArray(tok2);
}
@ -361,7 +352,6 @@ void CheckAutoVariables::returnReference()
tok2 = tok2->link();
unsigned int indentlevel = 0;
std::set<unsigned int> localvar; // local variables in function
for (; tok2; tok2 = tok2->next())
{
// indentlevel..
@ -374,33 +364,14 @@ void CheckAutoVariables::returnReference()
--indentlevel;
}
// declare local variable..
if (Token::Match(tok2, "[{};] %type%") && tok2->next()->str() != "return")
{
// goto next token..
tok2 = tok2->next();
// skip "const"
if (Token::Match(tok2, "const %type%"))
tok2 = tok2->next();
// skip "std::" if it is seen
if (Token::simpleMatch(tok2, "std ::"))
tok2 = tok2->tokAt(2);
// is it a variable declaration?
if (Token::Match(tok2, "%type% %var% ;"))
localvar.insert(tok2->next()->varId());
else if (Token::Match(tok2, "%type% < %any% > %var% ;"))
localvar.insert(tok2->tokAt(4)->varId());
}
// return..
else if (Token::Match(tok2, "return %var% ;"))
if (Token::Match(tok2, "return %var% ;"))
{
// is the returned variable a local variable?
if ((tok2->next()->varId() > 0) &&
(localvar.find(tok2->next()->varId()) != localvar.end()))
const unsigned int varid = tok2->next()->varId();
const Variable *var = symbolDatabase->getVariableFromVarId(varid);
if (var && var->isLocal() && !var->isStatic())
{
// report error..
errorReturnReference(tok2);
@ -462,7 +433,6 @@ void CheckAutoVariables::returncstr()
tok2 = tok2->next()->link();
unsigned int indentlevel = 0;
std::set<unsigned int> localvar; // local variables in function
for (; tok2; tok2 = tok2->next())
{
// indentlevel..
@ -475,31 +445,14 @@ void CheckAutoVariables::returncstr()
--indentlevel;
}
// declare local variable..
if (Token::Match(tok2, "[{};] %type%") && tok2->next()->str() != "return")
{
// goto next token..
tok2 = tok2->next();
// skip "const"
if (Token::Match(tok2, "const %type%"))
tok2 = tok2->next();
// skip "std::" if it is seen
if (Token::simpleMatch(tok2, "std ::"))
tok2 = tok2->tokAt(2);
// is it a variable declaration?
if (Token::Match(tok2, "%type% %var% [;=]"))
localvar.insert(tok2->next()->varId());
}
// return..
else if (Token::Match(tok2, "return %var% . c_str ( ) ;"))
if (Token::Match(tok2, "return %var% . c_str ( ) ;"))
{
// is the returned variable a local variable?
if ((tok2->next()->varId() > 0) &&
(localvar.find(tok2->next()->varId()) != localvar.end()))
const unsigned int varid = tok2->next()->varId();
const Variable *var = symbolDatabase->getVariableFromVarId(varid);
if (var && var->isLocal() && !var->isStatic())
{
// report error..
errorReturnAutocstr(tok2);

View File

@ -178,10 +178,6 @@ std::string Preprocessor::read(std::istream &istr, const std::string &filename,
// Remove all comments..
result = removeComments(result, filename, settings);
// Remove '#if 0' blocks
if (result.find("#if 0\n") != std::string::npos)
result = removeIf0(result);
// ------------------------------------------------------------------------------------------
//
// Clean up all preprocessor statements
@ -192,6 +188,10 @@ std::string Preprocessor::read(std::istream &istr, const std::string &filename,
// Clean up preprocessor #if statements with Parantheses
result = removeParantheses(result);
// Remove '#if 0' blocks
if (result.find("#if 0\n") != std::string::npos)
result = removeIf0(result);
return result;
}
@ -563,19 +563,33 @@ std::string Preprocessor::removeIf0(const std::string &code)
else
{
// replace '#if 0' with empty line
ret << "\n";
ret << line << "\n";
// goto the end of the '#if 0' block
unsigned int level = 1;
bool in = false;
while (level > 0 && std::getline(istr,line))
{
if (line.compare(0,3,"#if") == 0)
++level;
else if (line == "#endif")
--level;
else if (line == "#else")
{
if (level == 1)
in = true;
}
else
{
if (in)
ret << line << "\n";
else
// replace code within '#if 0' block with empty lines
ret << "\n";
continue;
}
ret << line << "\n";
}
}
}

View File

@ -623,22 +623,7 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
scope = *it;
if (scope->isClassOrStruct() && scope->needInitialization == Scope::Unknown)
{
std::list<ErrorLogger::ErrorMessage::FileLocation> locationList;
ErrorLogger::ErrorMessage::FileLocation loc;
loc.line = scope->classDef->linenr();
loc.setfile(_tokenizer->file(scope->classDef));
locationList.push_back(loc);
const ErrorLogger::ErrorMessage errmsg(locationList,
Severity::debug,
"SymbolDatabase::SymbolDatabase couldn't resolve all user defined types.",
"debug");
if (_errorLogger)
_errorLogger->reportErr(errmsg);
else
Check::reportError(errmsg);
}
debugMessage(scope->classDef, "SymbolDatabase::SymbolDatabase couldn't resolve all user defined types.");
}
}
@ -1078,6 +1063,27 @@ const Token *SymbolDatabase::initBaseInfo(Scope *scope, const Token *tok)
return tok2;
}
void SymbolDatabase::debugMessage(const Token *tok, const std::string &msg) const
{
if (tok && _settings->debugwarnings)
{
std::list<ErrorLogger::ErrorMessage::FileLocation> locationList;
ErrorLogger::ErrorMessage::FileLocation loc;
loc.line = tok->linenr();
loc.setfile(_tokenizer->file(tok));
locationList.push_back(loc);
const ErrorLogger::ErrorMessage errmsg(locationList,
Severity::debug,
msg,
"debug");
if (_errorLogger)
_errorLogger->reportErr(errmsg);
else
Check::reportError(errmsg);
}
}
//---------------------------------------------------------------------------
unsigned int Function::argCount() const
@ -1124,6 +1130,7 @@ void Function::addArguments(const SymbolDatabase *symbolDatabase, const Scope *s
const Token *endTok;
const Token *nameTok;
bool isConstVar;
bool isArrayVar;
const Token *tok = arg->next();
for (;;)
{
@ -1131,6 +1138,7 @@ void Function::addArguments(const SymbolDatabase *symbolDatabase, const Scope *s
endTok = NULL;
nameTok = NULL;
isConstVar = bool(tok->str() == "const");
isArrayVar = false;
while (tok->str() != "," && tok->str() != ")")
{
@ -1139,12 +1147,28 @@ void Function::addArguments(const SymbolDatabase *symbolDatabase, const Scope *s
nameTok = tok;
endTok = tok->previous();
}
else if (tok->str() == "[")
isArrayVar = true;
tok = tok->next();
}
// check for argument with no name
// check for argument with no name or missing varid
if (!endTok)
{
if (tok->previous()->isName())
{
if (tok->previous() != startTok->tokAt(isConstVar ? 1 : 0))
{
nameTok = tok->previous();
endTok = nameTok->previous();
symbolDatabase->debugMessage(nameTok, "Function::addArguments found argument \'" + nameTok->str() + "\' with varid 0.");
}
}
else
endTok = tok->previous();
}
const Token *typeTok = startTok;
if (isConstVar)
@ -1156,7 +1180,7 @@ void Function::addArguments(const SymbolDatabase *symbolDatabase, const Scope *s
bool isClassVar = startTok == endTok && !startTok->isStandardType();
argumentList.push_back(Variable(nameTok, startTok, endTok, count++, Argument, false, false, isConstVar, isClassVar, argType, scope, false));
argumentList.push_back(Variable(nameTok, startTok, endTok, count++, Argument, false, false, isConstVar, isClassVar, argType, scope, isArrayVar));
if (tok->str() == ")")
break;
@ -1429,23 +1453,8 @@ void Scope::getVariableList()
// If the vartok was set in the if-blocks above, create a entry for this variable..
if (vartok && vartok->str() != "operator")
{
if (vartok->varId() == 0 && !vartok->isBoolean() && check->_settings->debugwarnings)
{
std::list<ErrorLogger::ErrorMessage::FileLocation> locationList;
ErrorLogger::ErrorMessage::FileLocation loc;
loc.line = vartok->linenr();
loc.setfile(check->_tokenizer->file(vartok));
locationList.push_back(loc);
const ErrorLogger::ErrorMessage errmsg(locationList,
Severity::debug,
"Scope::getVariableList found variable \'" + vartok->str() + "\' with varid 0.",
"debug");
if (check->_errorLogger)
check->_errorLogger->reportErr(errmsg);
else
Check::reportError(errmsg);
}
if (vartok->varId() == 0 && !vartok->isBoolean())
check->debugMessage(vartok, "Scope::getVariableList found variable \'" + vartok->str() + "\' with varid 0.");
const Scope *scope = NULL;

View File

@ -500,6 +500,11 @@ public:
return _variableList[varId];
}
/**
* @brief output a debug message
*/
void debugMessage(const Token *tok, const std::string &msg) const;
private:
// Needed by Borland C++:

View File

@ -1790,6 +1790,7 @@ void Tokenizer::simplifyTypedef()
{
if (!inCast && !inSizeof)
tok2 = tok2->next();
tok2 = copyTokens(tok2, arrayStart, arrayEnd);
tok2 = tok2->next();
@ -4600,9 +4601,6 @@ void Tokenizer::simplifyIfAddBraces()
continue;
}
if (tok->previous() && !Token::Match(tok->previous(), ";|{|}|else|)|:"))
continue;
if (Token::Match(tok, "if|for|while ("))
{
// don't add "{}" around ";" in "do {} while();" (#609)
@ -6639,6 +6637,12 @@ bool Tokenizer::simplifyKnownVariablesSimplify(Token **tok2, Token *tok3, unsign
Token::Match(tok3, ("!|==|!=|<|<=|>|>= " + structname + " %varid% ==|!=|<|<=|>|>=|)|;").c_str(), varid) ||
Token::Match(tok3->previous(), "strlen|free ( %varid% )", varid))
{
if (value[0] == '\"' && tok3->strAt(-1) != "strlen")
{
// bail out if value is a string unless if it's just given
// as parameter to strlen
break;
}
if (!structname.empty())
{
tok3->deleteNext();
@ -6737,6 +6741,8 @@ bool Tokenizer::simplifyKnownVariablesSimplify(Token **tok2, Token *tok3, unsign
Token::Match(tok3, ("<<|>> " + structname + " %varid% [+-*/%^|;])]").c_str(), varid) ||
Token::Match(tok3->previous(), ("[=+-*/%^|[] ( " + structname + " %varid%").c_str(), varid))
{
if (value[0] == '\"')
break;
if (!structname.empty())
{
tok3->deleteNext();
@ -6853,13 +6859,14 @@ bool Tokenizer::simplifyKnownVariablesSimplify(Token **tok2, Token *tok3, unsign
// return variable..
if (Token::Match(tok3, "return %varid% %any%", varid) &&
isOp(tok3->tokAt(2)))
isOp(tok3->tokAt(2)) &&
value[0] != '\"')
{
tok3->next()->str(value);
tok3->next()->varId(valueVarId);
}
else if (pointeralias && Token::Match(tok3, "return * %varid% ;", varid))
else if (pointeralias && Token::Match(tok3, "return * %varid% ;", varid) && value[0] != '\"')
{
tok3->deleteNext();
tok3->next()->str(value);
@ -9124,7 +9131,8 @@ void Tokenizer::simplifyBitfields()
{
Token *last = 0;
if (Token::Match(tok, ";|{|}|public:|protected:|private: const| %type% %var% : %any% ;|,"))
if (Token::Match(tok, ";|{|}|public:|protected:|private: const| %type% %var% : %any% ;|,") &&
tok->next()->str() != "case")
{
int offset = 0;
if (tok->next()->str() == "const")
@ -9133,7 +9141,8 @@ void Tokenizer::simplifyBitfields()
last = tok->tokAt(5 + offset);
Token::eraseTokens(tok->tokAt(2 + offset), tok->tokAt(5 + offset));
}
else if (Token::Match(tok, ";|{|}|public:|protected:|private: const| %type% : %any% ;"))
else if (Token::Match(tok, ";|{|}|public:|protected:|private: const| %type% : %any% ;") &&
tok->next()->str() != "default")
{
int offset = 0;
if (tok->next()->str() == "const")
@ -9349,26 +9358,56 @@ const SymbolDatabase *Tokenizer::getSymbolDatabase() const
void Tokenizer::simplifyOperatorName()
{
for (const Token *tok = _tokens; tok; tok = tok->next())
for (Token *tok = _tokens; tok; tok = tok->next())
{
if (Token::Match(tok, ") const| {|;|="))
if (tok->str() == "operator")
{
Token *tok1 = tok->link();
Token *tok2 = tok1;
// operator op
std::string op;
Token *par = tok->next();
bool done = false;
while (!done && par)
{
done = true;
if (par && par->isName())
{
op += par->str();
par = par->next();
done = false;
}
if (Token::Match(par, "[<>+-*&/=.]") || Token::Match(par, "==|!=|<=|>="))
{
op += par->str();
par = par->next();
done = false;
}
if (Token::simpleMatch(par, "[ ]"))
{
op += "[]";
par = par->next()->next();
done = false;
}
if (Token::Match(par, "( *| )"))
{
// break out and simplify..
if (Token::Match(par, "( ) const| [=;{),]"))
break;
tok1 = tok1->previous();
while (tok1 && !Token::Match(tok1, "operator|{|}|;|public:|private|protected:"))
while (par->str() != ")")
{
tok1 = tok1->previous();
op += par->str();
par = par->next();
}
op += ")";
par = par->next();
done = false;
}
}
if (tok1 && tok1->str() == "operator")
if (par && Token::Match(par->link(), ") const| [=;{),]"))
{
while (tok1->next() != tok2)
{
tok1->str(tok1->str() + tok1->next()->str());
tok1->deleteNext();
}
tok->str("operator" + op);
Token::eraseTokens(tok,par);
}
}
}

View File

@ -216,7 +216,7 @@ private:
" EventPtr event = *eventP;\n"
" *actionsP = &event->actions;\n"
"}\n");
ASSERT_EQUALS(std::string(""), errout.str());
TODO_ASSERT_EQUALS("", "[test.cpp:1]: (debug) Function::addArguments found argument 'eventP' with varid 0.\n", errout.str());
}
void returnLocalVariable1()

View File

@ -92,6 +92,11 @@ private:
TEST_CASE(error3);
TEST_CASE(if0_exclude);
TEST_CASE(if0_whitespace);
TEST_CASE(if0_else);
TEST_CASE(if0_elif);
// Don't handle include in a #if 0 block
TEST_CASE(if0_include_1);
TEST_CASE(if0_include_2);
@ -641,6 +646,74 @@ private:
ASSERT_EQUALS("[test.c:1]: (error) #error hello world!\n", errout.str());
}
void if0_exclude()
{
Settings settings;
Preprocessor preprocessor(&settings, this);
std::istringstream code("#if 0\n"
"A\n"
"#endif\n"
"B\n");
ASSERT_EQUALS("#if 0\n\n#endif\nB\n", preprocessor.read(code,"",NULL));
std::istringstream code2("#if (0)\n"
"A\n"
"#endif\n"
"B\n");
ASSERT_EQUALS("#if 0\n\n#endif\nB\n", preprocessor.read(code2,"",NULL));
}
void if0_whitespace()
{
Settings settings;
Preprocessor preprocessor(&settings, this);
std::istringstream code(" # if 0 \n"
"A\n"
" # endif \n"
"B\n");
ASSERT_EQUALS("#if 0\n\n#endif\nB\n", preprocessor.read(code,"",NULL));
}
void if0_else()
{
Settings settings;
Preprocessor preprocessor(&settings, this);
std::istringstream code("#if 0\n"
"A\n"
"#else\n"
"B\n"
"#endif\n"
"C\n");
ASSERT_EQUALS("#if 0\n\n#else\nB\n#endif\nC\n", preprocessor.read(code,"",NULL));
std::istringstream code2("#if 1\n"
"A\n"
"#else\n"
"B\n"
"#endif\n"
"C\n");
TODO_ASSERT_EQUALS("#if 1\nA\n#else\n\n#endif\nC\n",
"#if 1\nA\n#else\nB\n#endif\nC\n", preprocessor.read(code2,"",NULL));
}
void if0_elif()
{
Settings settings;
Preprocessor preprocessor(&settings, this);
std::istringstream code("#if 0\n"
"A\n"
"#elif 1\n"
"B\n"
"#endif\n"
"C\n");
TODO_ASSERT_EQUALS("#if 0\n\n#elif 1\nB\n#endif\nC\n",
"#if 0\n\n\n\n#endif\nC\n", preprocessor.read(code,"",NULL));
}
void if0_include_1()
{
Settings settings;
@ -650,7 +723,7 @@ private:
"#include \"a.h\"\n"
"#endif\n"
"AB\n");
ASSERT_EQUALS("\n\n\nAB\n", preprocessor.read(code,"",NULL));
ASSERT_EQUALS("#if 0\n\n#endif\nAB\n", preprocessor.read(code,"",NULL));
}
void if0_include_2()
@ -665,7 +738,7 @@ private:
"#endif\n"
"#endif\n"
"AB\n");
ASSERT_EQUALS("\n\n\n\n\n\nAB\n", preprocessor.read(code,"",NULL));
ASSERT_EQUALS("#if 0\n\n#ifdef WIN32\n#else\n#endif\n#endif\nAB\n", preprocessor.read(code,"",NULL));
}
void includeguard1()

View File

@ -80,6 +80,7 @@ private:
TEST_CASE(ifAddBraces12);
TEST_CASE(ifAddBraces13);
TEST_CASE(ifAddBraces14); // #2610 - segfault: if()<{}
TEST_CASE(ifAddBraces15); // #2616 - unknown macro before if
TEST_CASE(whileAddBraces);
TEST_CASE(doWhileAddBraces);
@ -305,7 +306,10 @@ private:
// Tokenize JAVA
TEST_CASE(java);
TEST_CASE(simplifyOperatorName);
TEST_CASE(simplifyOperatorName1);
TEST_CASE(simplifyOperatorName2);
TEST_CASE(simplifyOperatorName3);
TEST_CASE(simplifyOperatorName4);
// Some simple cleanups of unhandled macros in the global scope
TEST_CASE(removeMacrosInGlobalScope);
@ -858,6 +862,12 @@ private:
tokenizeAndStringify("if()<{}", false);
}
void ifAddBraces15()
{
// ticket #2616 - unknown macro before if
ASSERT_EQUALS("{ A if ( x ) { y ( ) ; } }", tokenizeAndStringify("{A if(x)y();}", false));
}
void whileAddBraces()
{
@ -2042,6 +2052,7 @@ private:
}
void simplifyKnownVariables42()
{
{
const char code[] = "void f() {\n"
" char str1[10], str2[10];\n"
@ -2056,6 +2067,33 @@ private:
ASSERT_EQUALS(expected, tokenizeAndStringify(code, true));
}
{
const char code[] = "void f() {"
" char *s = malloc(10);"
" strcpy(s, \"\");"
" free(s);"
"}";
const char expected[] = "void f ( ) {"
" char * s ; s = malloc ( 10 ) ;"
" strcpy ( s , \"\" ) ;"
" free ( s ) ; "
"}";
ASSERT_EQUALS(expected, tokenizeAndStringify(code, true));
}
{
const char code[] = "void f(char *p, char *q) {"
" strcpy(p, \"abc\");"
" q = p;"
"}";
const char expected[] = "void f ( char * p , char * q ) {"
" strcpy ( p , \"abc\" ) ;"
" q = p ; "
"}";
ASSERT_EQUALS(expected, tokenizeAndStringify(code, true));
}
}
void simplifyKnownVariablesBailOutAssign()
{
const char code[] = "int foo() {\n"
@ -5118,6 +5156,12 @@ private:
const char code3[] = "struct A { bool : true; };";
ASSERT_EQUALS("struct A { } ;", tokenizeAndStringify(code3,false));
const char code4[] = "void f(int a) { switch (a) { case b: break; } }";
ASSERT_EQUALS("void f ( int a ) { switch ( a ) { case b : ; break ; } }", tokenizeAndStringify(code4,true));
const char code5[] = "void f(int a) { switch (a) { default: break; } }";
ASSERT_EQUALS("void f ( int a ) { switch ( a ) { default : ; break ; } }", tokenizeAndStringify(code5,true));
}
void microsoftMFC()
@ -5312,36 +5356,56 @@ private:
ASSERT_EQUALS("void f ( ) { }", javatest("void f() throws Exception { }"));
}
void simplifyOperatorName()
void simplifyOperatorName1()
{
// make sure C code doesn't get changed
const char code1[] = "void operator () {}"
const char code[] = "void operator () {}"
"int main()"
"{"
" operator();"
"}";
const char result1 [] = "void operator ( ) { } "
const char result [] = "void operator ( ) { } "
"int main ( ) "
"{ "
"operator ( ) ; "
"}";
ASSERT_EQUALS(result1, tokenizeAndStringify(code1,false));
ASSERT_EQUALS(result, tokenizeAndStringify(code,false));
}
const char code2[] = "class Fred"
void simplifyOperatorName2()
{
const char code[] = "class Fred"
"{"
" Fred(const Fred & f) { operator = (f); }"
" operator = ();"
"}";
const char result2 [] = "class Fred "
const char result [] = "class Fred "
"{ "
"Fred ( const Fred & f ) { operator= ( f ) ; } "
"operator= ( ) ; "
"}";
ASSERT_EQUALS(result2, tokenizeAndStringify(code2,false));
ASSERT_EQUALS(result, tokenizeAndStringify(code,false));
}
void simplifyOperatorName3()
{
// #2615
const char code[] = "void f() {"
"static_cast<ScToken*>(xResult.operator->())->GetMatrix();"
"}";
const char result[] = "void f ( ) { static_cast < ScToken * > ( xResult . operator. ( ) ) . GetMatrix ( ) ; }";
ASSERT_EQUALS(result, tokenizeAndStringify(code,false));
}
void simplifyOperatorName4()
{
const char code[] = "void operator==() { }";
const char result[] = "void operator== ( ) { }";
ASSERT_EQUALS(result, tokenizeAndStringify(code,false));
}
void removeMacrosInGlobalScope()