This commit is contained in:
Sébastien Debrard 2011-01-28 19:55:33 +01:00
commit 0f8946fd87
7 changed files with 309 additions and 7 deletions

View File

@ -129,7 +129,31 @@ bool CmdLineParser::ParseFromArgs(int argc, const char* const argv[])
}
// Filter errors
else if (strcmp(argv[i], "--suppressions") == 0)
else if (strncmp(argv[i], "--suppressions-list=", 20) == 0)
{
std::string filename = argv[i];
filename = filename.substr(20);
std::ifstream f(filename.c_str());
if (!f.is_open())
{
std::string message("cppcheck: Couldn't open the file \"");
message += std::string(filename);
message += "\"";
PrintMessage(message);
return false;
}
const std::string errmsg(_settings->nomsg.parseFile(f));
if (!errmsg.empty())
{
PrintMessage(errmsg);
return false;
}
}
// Filter errors
// This is deprecated, see --supressions-list above
else if (strcmp(argv[i], "--suppressions") == 0 &&
strlen(argv[i]) == 14)
{
++i;
@ -516,7 +540,7 @@ void CmdLineParser::PrintHelp()
" cppcheck [--append=file] [-D<ID>] [--enable=<id>] [--error-exitcode=[n]]\n"
" [--exitcode-suppressions file] [--file-list=file.txt] [--force]\n"
" [--help] [-Idir] [--inline-suppr] [-j [jobs]] [--quiet]\n"
" [--report-progress] [--style] [--suppressions file.txt]\n"
" [--report-progress] [--style] [--suppressions-list=file.txt]\n"
" [--verbose] [--version] [--xml] [file or path1] [file or path]\n"
"\n"
"If path is given instead of filename, *.cpp, *.cxx, *.cc, *.c++ and *.c files\n"
@ -540,6 +564,7 @@ void CmdLineParser::PrintHelp()
" if arguments are not valid or if no input files are\n"
" provided. Note that your operating system can\n"
" modify this value, e.g. 256 can become 0.\n"
" --errorlist Print a list of all error messages in XML format.\n"
" --exitcode-suppressions file\n"
" Used when certain messages should be displayed but\n"
" should not cause a non-zero exitcode.\n"
@ -557,8 +582,10 @@ void CmdLineParser::PrintHelp()
" -q, --quiet Only print error messages\n"
" --report-progress Report progress messages while checking a file.\n"
" -s, --style deprecated, use --enable=style\n"
" --suppressions file Suppress warnings listed in the file. Filename and line\n"
" are optional. The format of the single line in file is:\n"
" --suppressions-list=file\n"
" Suppress warnings listed in the file. Filename and line\n"
" are optional in the suppression file. The format of the\n"
" single line in the suppression file is:\n"
" [error id]:[filename]:[line]\n"
" --template '[text]' Format the error messages. E.g.\n"
" '{file}:{line},{severity},{id},{message}' or\n"

View File

@ -1348,6 +1348,42 @@ const Scope *SymbolDatabase::findVariableType(const Scope *start, const Token *t
//---------------------------------------------------------------------------
const Scope *SymbolDatabase::findFunctionScopeByToken(const Token *tok) const
{
std::list<Scope *>::const_iterator scope;
for (scope = scopeList.begin(); scope != scopeList.end(); ++scope)
{
if ((*scope)->type == Scope::eFunction)
{
if ((*scope)->classDef == tok)
return (*scope);
}
}
return 0;
}
//---------------------------------------------------------------------------
const Function *SymbolDatabase::findFunctionByToken(const Token *tok) const
{
std::list<Scope *>::const_iterator scope;
for (scope = scopeList.begin(); scope != scopeList.end(); ++scope)
{
std::list<Function>::const_iterator func;
for (func = (*scope)->functionList.begin(); func != (*scope)->functionList.end(); ++func)
{
if (func->token == tok)
return &*func;
}
}
return 0;
}
//---------------------------------------------------------------------------
Scope * Scope::findInNestedList(const std::string & name)
{
std::list<Scope *>::iterator it;

View File

@ -362,6 +362,10 @@ public:
*/
const Scope *findVariableType(const Scope *start, const Token *type) const;
const Scope *findFunctionScopeByToken(const Token *tok) const;
const Function *findFunctionByToken(const Token *tok) const;
bool argsMatch(const Scope *info, const Token *first, const Token *second, const std::string &path, unsigned int depth) const;
bool isClassOrStruct(const std::string &type) const

View File

@ -2041,6 +2041,16 @@ bool Tokenizer::tokenize(std::istream &code,
}
}
// if MACRO
for (const Token *tok = _tokens; tok; tok = tok->next())
{
if (Token::Match(tok, "if|for|while %var% ("))
{
syntaxError(tok);
return false;
}
}
// Simplify JAVA/C# code
if (isJavaOrCSharp() && _files[0].find(".java") != std::string::npos)
{
@ -6836,7 +6846,7 @@ bool Tokenizer::simplifyRedundantParanthesis()
ret = true;
}
while (Token::Match(tok->previous(), "[;{(] ( %var% (") &&
while (Token::Match(tok->previous(), "[,;{}(] ( %var% (") &&
tok->link()->previous() == tok->tokAt(2)->link())
{
// We have "( func ( *something* ))", remove the outer

View File

@ -72,7 +72,9 @@ private:
TEST_CASE(jobsMissingCount);
TEST_CASE(jobsInvalid);
TEST_CASE(reportProgress);
TEST_CASE(suppressions); // TODO: Create and test real suppression file
TEST_CASE(suppressionsOld); // TODO: Create and test real suppression file
TEST_CASE(suppressions)
TEST_CASE(suppressionsNoFile)
TEST_CASE(templates);
TEST_CASE(templatesGcc);
TEST_CASE(templatesVs);
@ -492,8 +494,9 @@ private:
ASSERT(settings.reportProgress);
}
void suppressions()
void suppressionsOld()
{
// TODO: Fails because there is no suppr.txt file!
REDIRECT;
const char *argv[] = {"cppcheck", "--suppressions suppr.txt", "file.cpp"};
Settings settings;
@ -501,6 +504,25 @@ private:
ASSERT(!parser.ParseFromArgs(3, argv));
}
void suppressions()
{
// TODO: Fails because there is no suppr.txt file!
REDIRECT;
const char *argv[] = {"cppcheck", "--suppressions-list=suppr.txt", "file.cpp"};
Settings settings;
CmdLineParser parser(&settings);
ASSERT(!parser.ParseFromArgs(3, argv));
}
void suppressionsNoFile()
{
REDIRECT;
const char *argv[] = {"cppcheck", "--suppressions-list=", "file.cpp"};
Settings settings;
CmdLineParser parser(&settings);
ASSERT(!parser.ParseFromArgs(3, argv));
}
void templates()
{
REDIRECT;

View File

@ -20,6 +20,14 @@
#include "testutils.h"
#include "symboldatabase.h"
#define GET_SYMBOL_DB(code) \
errout.str(""); \
Settings settings; \
Tokenizer tokenizer(&settings, this); \
std::istringstream istr(code); \
tokenizer.tokenize(istr, "test.cpp"); \
const SymbolDatabase *db = tokenizer.getSymbolDatabase();
class TestSymbolDatabase: public TestFixture
{
public:
@ -75,6 +83,16 @@ private:
TEST_CASE(canFindMatchingBracketsOuterPair);
TEST_CASE(canFindMatchingBracketsWithTooManyClosing);
TEST_CASE(canFindMatchingBracketsWithTooManyOpening);
TEST_CASE(hasRegularFunction);
TEST_CASE(hasInlineClassFunction);
TEST_CASE(hasMissingInlineClassFunction);
TEST_CASE(hasClassFunction);
TEST_CASE(hasRegularFunctionReturningFunctionPointer);
TEST_CASE(hasInlineClassFunctionReturningFunctionPointer);
TEST_CASE(hasMissingInlineClassFunctionReturningFunctionPointer);
TEST_CASE(hasClassFunctionReturningFunctionPointer);
}
void test_isVariableDeclarationCanHandleNull()
@ -336,6 +354,174 @@ private:
found = si.findClosingBracket(var.tokens()->tokAt(1), t);
ASSERT(!found);
}
void hasRegularFunction()
{
GET_SYMBOL_DB("void func() { }\n")
// 2 scopes: Global and Function
ASSERT(db && db->scopeList.size() == 2 && tokenizer.getFunctionTokenByName("func"));
if (db)
{
const Scope *scope = db->findFunctionScopeByToken(tokenizer.tokens()->tokAt(1));
ASSERT(scope && scope->className == "func");
const Function *function = db->findFunctionByToken(tokenizer.tokens()->tokAt(1));
ASSERT(function && function->token->str() == "func");
ASSERT(function && function->token == tokenizer.tokens()->tokAt(1));
ASSERT(function && function->hasBody);
}
}
void hasInlineClassFunction()
{
GET_SYMBOL_DB("class Fred { void func() { } };\n")
// 3 scopes: Global, Class, and Function
ASSERT(db && db->scopeList.size() == 3 && tokenizer.getFunctionTokenByName("func"));
if (db)
{
const Scope *scope = db->findFunctionScopeByToken(tokenizer.tokens()->tokAt(4));
ASSERT(scope && scope->className == "func");
const Function *function = db->findFunctionByToken(tokenizer.tokens()->tokAt(4));
ASSERT(function && function->token->str() == "func");
ASSERT(function && function->token == tokenizer.tokens()->tokAt(4));
ASSERT(function && function->hasBody && function->isInline);
}
}
void hasMissingInlineClassFunction()
{
GET_SYMBOL_DB("class Fred { void func(); };\n")
// 2 scopes: Global and Class (no Function scope because there is no function implementation)
ASSERT(db && db->scopeList.size() == 2 && !tokenizer.getFunctionTokenByName("func"));
if (db)
{
const Scope *scope = db->findFunctionScopeByToken(tokenizer.tokens()->tokAt(4));
ASSERT(scope == NULL);
const Function *function = db->findFunctionByToken(tokenizer.tokens()->tokAt(4));
ASSERT(function && function->token->str() == "func");
ASSERT(function && function->token == tokenizer.tokens()->tokAt(4));
ASSERT(function && !function->hasBody);
}
}
void hasClassFunction()
{
GET_SYMBOL_DB("class Fred { void func(); }; Fred::func() { }\n")
// 3 scopes: Global, Class, and Function
ASSERT(db && db->scopeList.size() == 3 && tokenizer.getFunctionTokenByName("func"));
if (db)
{
const Scope *scope = db->findFunctionScopeByToken(tokenizer.tokens()->tokAt(12));
ASSERT(scope && scope->className == "func");
const Function *function = db->findFunctionByToken(tokenizer.tokens()->tokAt(12));
ASSERT(function && function->token->str() == "func");
ASSERT(function && function->token == tokenizer.tokens()->tokAt(12));
ASSERT(function && function->hasBody && !function->isInline);
}
}
void hasRegularFunctionReturningFunctionPointer()
{
GET_SYMBOL_DB("void (*func(int f))(char) { }\n")
// 2 scopes: Global and Function
ASSERT(db && db->scopeList.size() == 2 && tokenizer.getFunctionTokenByName("func"));
if (db)
{
const Scope *scope = db->findFunctionScopeByToken(tokenizer.tokens()->tokAt(3));
ASSERT(scope && scope->className == "func");
const Function *function = db->findFunctionByToken(tokenizer.tokens()->tokAt(3));
ASSERT(function && function->token->str() == "func");
ASSERT(function && function->token == tokenizer.tokens()->tokAt(3));
ASSERT(function && function->hasBody && function->retFuncPtr);
}
}
void hasInlineClassFunctionReturningFunctionPointer()
{
GET_SYMBOL_DB("class Fred { void (*func(int f))(char) { } };\n")
// 3 scopes: Global, Class, and Function
ASSERT(db && db->scopeList.size() == 3 && tokenizer.getFunctionTokenByName("func"));
if (db)
{
const Scope *scope = db->findFunctionScopeByToken(tokenizer.tokens()->tokAt(6));
ASSERT(scope && scope->className == "func");
const Function *function = db->findFunctionByToken(tokenizer.tokens()->tokAt(6));
ASSERT(function && function->token->str() == "func");
ASSERT(function && function->token == tokenizer.tokens()->tokAt(6));
ASSERT(function && function->hasBody && function->isInline && function->retFuncPtr);
}
}
void hasMissingInlineClassFunctionReturningFunctionPointer()
{
GET_SYMBOL_DB("class Fred { void (*func(int f))(char); };\n")
// 2 scopes: Global and Class (no Function scope because there is no function implementation)
ASSERT(db && db->scopeList.size() == 2 && !tokenizer.getFunctionTokenByName("func"));
if (db)
{
const Scope *scope = db->findFunctionScopeByToken(tokenizer.tokens()->tokAt(6));
ASSERT(scope == NULL);
const Function *function = db->findFunctionByToken(tokenizer.tokens()->tokAt(6));
ASSERT(function && function->token->str() == "func");
ASSERT(function && function->token == tokenizer.tokens()->tokAt(6));
ASSERT(function && !function->hasBody && function->retFuncPtr);
}
}
void hasClassFunctionReturningFunctionPointer()
{
GET_SYMBOL_DB("class Fred { void (*func(int f))(char); }; void (*Fred::func(int f))(char) { }\n")
// 3 scopes: Global, Class, and Function
ASSERT(db && db->scopeList.size() == 3 && tokenizer.getFunctionTokenByName("func"));
if (db)
{
const Scope *scope = db->findFunctionScopeByToken(tokenizer.tokens()->tokAt(23));
ASSERT(scope && scope->className == "func");
const Function *function = db->findFunctionByToken(tokenizer.tokens()->tokAt(23));
ASSERT(function && function->token->str() == "func");
ASSERT(function && function->token == tokenizer.tokens()->tokAt(23));
ASSERT(function && function->hasBody && !function->isInline && function->retFuncPtr);
}
}
};
REGISTER_TEST(TestSymbolDatabase)

View File

@ -52,6 +52,7 @@ private:
// don't freak out when the syntax is wrong
TEST_CASE(wrong_syntax);
TEST_CASE(wrong_syntax_if_macro); // #2518 - if MACRO()
TEST_CASE(minus);
@ -204,6 +205,7 @@ private:
TEST_CASE(removeParantheses8); // Ticket #1865
TEST_CASE(removeParantheses9); // Ticket #1962
TEST_CASE(removeParantheses10); // Ticket #2320
TEST_CASE(removeParantheses11); // Ticket #2505
TEST_CASE(tokenize_double);
TEST_CASE(tokenize_strings);
@ -522,6 +524,15 @@ private:
}
}
void wrong_syntax_if_macro()
{
// #2518
errout.str("");
const std::string code("void f() { if MACRO(); }");
tokenizeAndStringify(code.c_str(), false);
ASSERT_EQUALS("[test.cpp:1]: (error) syntax error\n", errout.str());
}
void minus()
{
ASSERT_EQUALS("i = -12", tokenizeAndStringify("i = -12"));
@ -3678,6 +3689,12 @@ private:
ASSERT_EQUALS("p = buf + 8 ;", tokenizeAndStringify("p = (buf + 8);", false));
}
void removeParantheses11()
{
// #2502
ASSERT_EQUALS("{ } x ( ) ;", tokenizeAndStringify("{}(x());", false));
}
void tokenize_double()
{
const char code[] = "void f()\n"