Merge branch 'master' of http://github.com/danmar/cppcheck
This commit is contained in:
commit
0f8946fd87
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Reference in New Issue