void CheckUnusedFunctions::parseTokens(const Tokenizer &tokenizer, const char FileName[], const Settings *settings) { const SymbolDatabase* symbolDatabase = tokenizer.getSymbolDatabase(); // Function declarations.. for (std::size_t i = 0; i < symbolDatabase->functionScopes.size(); i++) { const Scope* scope = symbolDatabase->functionScopes[i]; const Function* func = scope->function; if (!func || !func->token || scope->classStart->fileIndex() != 0) continue; // Don't warn about functions that are marked by __attribute__((constructor)) or __attribute__((destructor)) if (func->isAttributeConstructor() || func->isAttributeDestructor() || func->type != Function::eFunction) continue; // Don't care about templates if (func->retDef->str() == "template") continue; FunctionUsage &usage = _functions[func->name()]; if (!usage.lineNumber) usage.lineNumber = func->token->linenr(); // No filename set yet.. if (usage.filename.empty()) { usage.filename = tokenizer.getSourceFilePath(); } // Multiple files => filename = "+" else if (usage.filename != tokenizer.getSourceFilePath()) { //func.filename = "+"; usage.usedOtherFile |= usage.usedSameFile; } } // Function usage.. for (const Token *tok = tokenizer.tokens(); tok; tok = tok->next()) { // parsing of library code to find called functions if (settings->library.isexecutableblock(FileName, tok->str())) { const Token * markupVarToken = tok->tokAt(settings->library.blockstartoffset(FileName)); int scope = 0; bool start = true; // find all function calls in library code (starts with '(', not if or while etc) while (scope || start) { if (markupVarToken->str() == settings->library.blockstart(FileName)) { scope++; if (start) { start = false; } } else if (markupVarToken->str() == settings->library.blockend(FileName)) scope--; else if (!settings->library.iskeyword(FileName, markupVarToken->str())) { if (_functions.find(markupVarToken->str()) != _functions.end()) _functions[markupVarToken->str()].usedOtherFile = true; else if (markupVarToken->next()->str() == "(") { FunctionUsage &func = _functions[markupVarToken->str()]; func.filename = tokenizer.getSourceFilePath(); if (func.filename.empty() || func.filename == "+") func.usedOtherFile = true; else func.usedSameFile = true; } } markupVarToken = markupVarToken->next(); } } if (!settings->library.markupFile(FileName) // only check source files && settings->library.isexporter(tok->str()) && tok->next() != 0) { const Token * qPropToken = tok; qPropToken = qPropToken->next(); while (qPropToken && qPropToken->str() != ")") { if (settings->library.isexportedprefix(tok->str(), qPropToken->str())) { const Token* qNextPropToken = qPropToken->next(); const std::string& value = qNextPropToken->str(); if (_functions.find(value) != _functions.end()) { _functions[value].usedOtherFile = true; } } if (settings->library.isexportedsuffix(tok->str(), qPropToken->str())) { const Token* qNextPropToken = qPropToken->previous(); const std::string& value = qNextPropToken->str(); if (value != ")" && _functions.find(value) != _functions.end()) { _functions[value].usedOtherFile = true; } } qPropToken = qPropToken->next(); } } if (settings->library.markupFile(FileName) && settings->library.isimporter(FileName, tok->str()) && tok->next()) { const Token * qPropToken = tok; qPropToken = qPropToken->next(); if (qPropToken->next()) { qPropToken = qPropToken->next(); while (qPropToken && qPropToken->str() != ")") { const std::string& value = qPropToken->str(); if (!value.empty()) { _functions[value].usedOtherFile = true; break; } qPropToken = qPropToken->next(); } } } if (settings->library.isreflection(tok->str())) { const int index = settings->library.reflectionArgument(tok->str()); if (index >= 0) { const Token * funcToken = tok->next(); int p = 0; std::string value; while (funcToken) { if (funcToken->str()==",") { if (++p==index) break; value = ""; } else value += funcToken->str(); funcToken = funcToken->next(); } if (p==index) { value = value.substr(1, value.length() - 2); _functions[value].usedOtherFile = true; } } } const Token *funcname = nullptr; if (tok->scope()->isExecutable() && Token::Match(tok->next(), "%var% (")) { funcname = tok->next(); } else if (tok->scope()->isExecutable() && Token::Match(tok->next(), "%var% <") && Token::simpleMatch(tok->linkAt(2), "> (")) { funcname = tok->next(); } else if (Token::Match(tok, "[;{}.,()[=+-/|!?:] &| %var% [(),;:}]")) { funcname = tok->next(); if (tok->str() == "&") funcname = funcname->next(); } else if (Token::Match(tok, "[;{}.,()[=+-/|!?:] &| %var% :: %var%")) { funcname = tok->next(); if (funcname->str() == "&") funcname = funcname->next(); while (Token::Match(funcname,"%var% :: %var%")) funcname = funcname->tokAt(2); if (!Token::Match(funcname, "%var% [(),;:}]")) continue; } else continue; // funcname ( => Assert that the end parentheses isn't followed by { if (Token::Match(funcname, "%var% (|<")) { const Token *ftok = funcname->next(); if (ftok->str() == "<") ftok = ftok->link(); if (Token::Match(ftok->linkAt(1), ") const|throw|{")) funcname = nullptr; } if (funcname) { FunctionUsage &func = _functions[ funcname->str()]; if (func.filename.empty() || func.filename == "+") func.usedOtherFile = true; else func.usedSameFile = true; } } }
void CheckUnusedFunctions::parseTokens(const Tokenizer &tokenizer) { // Function declarations.. for (const Token *tok = tokenizer.tokens(); tok; tok = tok->next()) { if (tok->fileIndex() != 0) continue; // token contains a ':' => skip to next ; or { if (tok->str().find(":") != std::string::npos) { while (tok && tok->str().find_first_of(";{")) tok = tok->next(); if (tok) continue; break; } // If this is a template function, skip it if (tok->previous() && tok->previous()->str() == ">") continue; const Token *funcname = 0; if (Token::Match(tok, "%type% %var% (")) funcname = tok->next(); else if (Token::Match(tok, "%type% *|& %var% (")) funcname = tok->tokAt(2); else if (Token::Match(tok, "%type% :: %var% (") && !Token::Match(tok, tok->strAt(2).c_str())) funcname = tok->tokAt(2); // Don't assume throw as a function name: void foo() throw () {} if (Token::Match(tok->previous(), ")|const") || funcname == 0) continue; tok = funcname->linkAt(1); // Check that ") {" is found.. if (! Token::simpleMatch(tok, ") {") && ! Token::simpleMatch(tok, ") const {") && ! Token::simpleMatch(tok, ") const throw ( ) {") && ! Token::simpleMatch(tok, ") throw ( ) {")) funcname = 0; if (funcname) { FunctionUsage &func = _functions[ funcname->str()]; if (!func.lineNumber) func.lineNumber = funcname->linenr(); // No filename set yet.. if (func.filename.empty()) { func.filename = tokenizer.getSourceFilePath(); } // Multiple files => filename = "+" else if (func.filename != tokenizer.getSourceFilePath()) { //func.filename = "+"; func.usedOtherFile |= func.usedSameFile; } } } // Function usage.. for (const Token *tok = tokenizer.tokens(); tok; tok = tok->next()) { const Token *funcname = 0; if (Token::Match(tok->next(), "%var% (")) { funcname = tok->next(); } else if (Token::Match(tok, "[;{}.,()[=+-/&|!?:] %var% [(),;:}]")) funcname = tok->next(); else if (Token::Match(tok, "[=(,] &| %var% :: %var%")) { funcname = tok->next(); if (funcname->str() == "&") funcname = funcname->next(); while (Token::Match(funcname,"%var% :: %var%")) funcname = funcname->tokAt(2); if (!Token::Match(funcname, "%var% [,);]")) continue; } else continue; // funcname ( => Assert that the end parenthesis isn't followed by { if (Token::Match(funcname, "%var% (")) { if (Token::Match(funcname->linkAt(1), ") const|{")) funcname = NULL; } if (funcname) { FunctionUsage &func = _functions[ funcname->str()]; if (func.filename.empty() || func.filename == "+") func.usedOtherFile = true; else func.usedSameFile = true; } } }
void MakeClassFunctionFunctionsTable::parseTokens(const Tokenizer &tokenizer) { symbolDatabase=tokenizer.getSymbolDatabase(); // Function declarations.. for (std::list<Scope>::const_iterator scope = symbolDatabase->scopeList.begin(); scope != symbolDatabase->scopeList.end(); ++scope) { if (scope->type != Scope::eClass) continue; functionFunctionTable[scope._Ptr->_Myval.className]; for (const Token *tok = scope->classDef->next(); tok && tok != scope->classEnd; tok = tok->next()) { const Token *funcname = 0; if (Token::Match(tok, "%type% %var% (")) funcname = tok->next(); else if (Token::Match(tok, "%type% *|& %var% (")) funcname = tok->tokAt(2); // Don't assume throw as a function name: void foo() throw () {} if (Token::Match(tok->previous(), ")|const") || funcname == 0) continue; tok = funcname->linkAt(1); if (funcname) { FunctionDeclaration &func = _functions[ funcname->str()]; if (!func.lineNumber) func.lineNumber = funcname->linenr(); // No filename set yet.. if (func.filename.empty()) { func.filename = tokenizer.getSourceFilePath(); } if(func.scopeName.empty()) { func.scopeName = tok->scope()->className; func.scopeType = tok->scope()->type; } } } } // Function usage.. for (std::list<Scope>::const_iterator scope = symbolDatabase->scopeList.begin(); scope != symbolDatabase->scopeList.end(); ++scope) { // only check functions if (scope->type != Scope::eFunction) continue; if(_functions[scope->className].scopeName.empty() || _functions[scope->className].scopeType!=Scope::eClass) continue; for (const Token *tok = scope->classDef->next(); tok && tok != scope->classEnd; tok = tok->next()) { const Token *funcname = 0; if (Token::Match(tok->next(), "%var% (")) { funcname = tok->next(); } else if (Token::Match(tok, "[;{}.,()[=+-/&|!?:] %var% [(),;:}]")) funcname = tok->next(); else if (Token::Match(tok, "[=(,] &| %var% :: %var%")) { funcname = tok->next(); if (funcname->str() == "&") funcname = funcname->next(); while (Token::Match(funcname,"%var% :: %var%")) funcname = funcname->tokAt(2); if (!Token::Match(funcname, "%var% [,);]")) continue; } else continue; // funcname ( => Assert that the end parenthesis isn't followed by { if (Token::Match(funcname, "%var% (")) { if (Token::Match(funcname->linkAt(1), ") const|{")) funcname = NULL; } if (funcname) { if(_functions[funcname->str()].scopeName.empty() || _functions[funcname->str()].scopeType!=Scope::eClass) continue; //사용기록 저장 std::pair<bool, // read or write std::pair< std::string, //file path unsigned int //code line >> a; a.first=false; a.second.first=tokenizer.getSourceFilePath(); a.second.second=funcname->linenr(); std::list<std::pair<bool,std::pair< std::string,unsigned int>>>::iterator it; for(it=functionFunctionTable[_functions[funcname->str()].scopeName][funcname->str()][scope->className].begin(); it!=functionFunctionTable[_functions[funcname->str()].scopeName][funcname->str()][scope->className].end(); ++it) { if(it->second.first.find(a.first) && it->second.second==a.second.second) break; } if(it==functionFunctionTable[_functions[funcname->str()].scopeName][funcname->str()][scope->className].end()) functionFunctionTable[_functions[funcname->str()].scopeName][funcname->str()][scope->className].push_back(a); } } } }
void CheckUnusedFunctions::parseTokens(const Tokenizer &tokenizer, const char FileName[], const Settings *settings) { // Function declarations.. for (const Token *tok = tokenizer.tokens(); tok; tok = tok->next()) { if (tok->fileIndex() != 0) continue; // token contains a ':' => skip to next ; or { if (tok->str().find(":") != std::string::npos) { while (tok && tok->str().find_first_of(";{")) tok = tok->next(); if (tok) continue; break; } // If this is a template function, skip it if (tok->previous() && tok->previous()->str() == ">") continue; const Token *funcname = 0; if (Token::Match(tok, "%type% %var% (")) funcname = tok->next(); else if (Token::Match(tok, "%type% *|& %var% (")) funcname = tok->tokAt(2); else if (Token::Match(tok, "%type% :: %var% (") && !Token::Match(tok, tok->strAt(2).c_str())) funcname = tok->tokAt(2); // Don't assume throw as a function name: void foo() throw () {} if (Token::Match(tok->previous(), ")|const") || funcname == 0) continue; // Don't warn about functions that are marked by __attribute__((constructor)) if (tok->isAttributeConstructor() || funcname->isAttributeConstructor()) continue; tok = funcname->linkAt(1); // Check that ") {" is found.. if (! Token::Match(tok, ") const| {") && ! Token::Match(tok, ") const| throw ( ) {")) funcname = 0; if (funcname) { FunctionUsage &func = _functions[ funcname->str()]; if (!func.lineNumber) func.lineNumber = funcname->linenr(); // No filename set yet.. if (func.filename.empty()) { func.filename = tokenizer.getSourceFilePath(); } // Multiple files => filename = "+" else if (func.filename != tokenizer.getSourceFilePath()) { //func.filename = "+"; func.usedOtherFile |= func.usedSameFile; } } } // Function usage.. const Token *scopeEnd = NULL; for (const Token *tok = tokenizer.tokens(); tok; tok = tok->next()) { // parsing of library code to find called functions if (settings->library.isexecutableblock(FileName, tok->str())) { const Token * markupVarToken = tok->tokAt(settings->library.blockstartoffset(FileName)); int scope = 1; // find all function calls in library code (starts with '(', not if or while etc) while (scope) { if (markupVarToken->str() == settings->library.blockstart(FileName)) { scope++; } else if (markupVarToken->str() == settings->library.blockend(FileName)) scope--; else if (!settings->library.iskeyword(FileName, markupVarToken->str())) { if (_functions.find(markupVarToken->str()) != _functions.end()) _functions[markupVarToken->str()].usedOtherFile = true; else if (markupVarToken->next()->str() == "(") { FunctionUsage &func = _functions[markupVarToken->str()]; func.filename = tokenizer.getSourceFilePath(); if (func.filename.empty() || func.filename == "+") func.usedOtherFile = true; else func.usedSameFile = true; } } markupVarToken = markupVarToken->next(); } } if (!settings->library.markupFile(FileName) // only check source files && settings->library.isexporter(tok->str()) && tok->next() != 0) { const Token * qPropToken = tok; qPropToken = qPropToken->next(); while (qPropToken && qPropToken->str() != ")") { if (settings->library.isexportedprefix(tok->str(), qPropToken->str())) { const Token* qNextPropToken = qPropToken->next(); const std::string value = qNextPropToken->str(); if (_functions.find(value) != _functions.end()) { _functions[value].usedOtherFile = true; } } if (settings->library.isexportedsuffix(tok->str(), qPropToken->str())) { const Token* qNextPropToken = qPropToken->previous(); const std::string value = qNextPropToken->str(); if (value != ")" && _functions.find(value) != _functions.end()) { _functions[value].usedOtherFile = true; } } qPropToken = qPropToken->next(); } } if (settings->library.markupFile(FileName) && settings->library.isimporter(FileName, tok->str()) && tok->next()) { const Token * qPropToken = tok; qPropToken = qPropToken->next(); if (qPropToken->next()) { qPropToken = qPropToken->next(); while (qPropToken && qPropToken->str() != ")") { const std::string value = qPropToken->str(); if (!value.empty()) { _functions[value].usedOtherFile = true; break; } qPropToken = qPropToken->next(); } } } if (settings->library.isreflection(FileName, tok->str())) { const int index = settings->library.reflectionArgument(FileName, tok->str()); if (index >= 0) { const Token * funcToken = tok->tokAt(index); if (funcToken) { std::string value = funcToken->str(); value = value.substr(1, value.length() - 2); _functions[value].usedOtherFile = true; } } } if (scopeEnd == NULL) { if (!Token::Match(tok, ")|= const| {")) continue; scopeEnd = tok; while (scopeEnd->str() != "{") scopeEnd = scopeEnd->next(); scopeEnd = scopeEnd->link(); } else if (tok == scopeEnd) { scopeEnd = NULL; continue; } const Token *funcname = 0; if (Token::Match(tok->next(), "%var% (")) { funcname = tok->next(); } else if (Token::Match(tok->next(), "%var% <") && Token::simpleMatch(tok->linkAt(2), "> (")) { funcname = tok->next(); } else if (Token::Match(tok, "[;{}.,()[=+-/&|!?:] %var% [(),;:}]")) funcname = tok->next(); else if (Token::Match(tok, "[=(,] &| %var% :: %var%")) { funcname = tok->next(); if (funcname->str() == "&") funcname = funcname->next(); while (Token::Match(funcname,"%var% :: %var%")) funcname = funcname->tokAt(2); if (!Token::Match(funcname, "%var% [,);]")) continue; } else continue; // funcname ( => Assert that the end parentheses isn't followed by { if (Token::Match(funcname, "%var% (|<")) { const Token *ftok = funcname->next(); if (ftok->str() == "<") ftok = ftok->link(); if (Token::Match(ftok->linkAt(1), ") const|throw|{")) funcname = NULL; } if (funcname) { FunctionUsage &func = _functions[ funcname->str()]; if (func.filename.empty() || func.filename == "+") func.usedOtherFile = true; else func.usedSameFile = true; } } }
void CppCheck::executeRules(const std::string &tokenlist, const Tokenizer &tokenizer) { (void)tokenlist; (void)tokenizer; #ifdef HAVE_RULES // Are there rules to execute? bool isrule = false; for (std::list<Settings::Rule>::const_iterator it = _settings.rules.begin(); it != _settings.rules.end(); ++it) { if (it->tokenlist == tokenlist) isrule = true; } // There is no rule to execute if (isrule == false) return; // Write all tokens in a string that can be parsed by pcre std::ostringstream ostr; for (const Token *tok = tokenizer.tokens(); tok; tok = tok->next()) ostr << " " << tok->str(); const std::string str(ostr.str()); for (std::list<Settings::Rule>::const_iterator it = _settings.rules.begin(); it != _settings.rules.end(); ++it) { const Settings::Rule &rule = *it; if (rule.pattern.empty() || rule.id.empty() || rule.severity.empty() || rule.tokenlist != tokenlist) continue; const char *error = 0; int erroffset = 0; pcre *re = pcre_compile(rule.pattern.c_str(),0,&error,&erroffset,NULL); if (!re) { if (error) { ErrorLogger::ErrorMessage errmsg(std::list<ErrorLogger::ErrorMessage::FileLocation>(), Severity::error, error, "pcre_compile", false); reportErr(errmsg); } continue; } int pos = 0; int ovector[30]; while (pos < (int)str.size() && 0 <= pcre_exec(re, NULL, str.c_str(), (int)str.size(), pos, 0, ovector, 30)) { unsigned int pos1 = (unsigned int)ovector[0]; unsigned int pos2 = (unsigned int)ovector[1]; // jump to the end of the match for the next pcre_exec pos = (int)pos2; // determine location.. ErrorLogger::ErrorMessage::FileLocation loc; loc.setfile(tokenizer.getSourceFilePath()); loc.line = 0; std::size_t len = 0; for (const Token *tok = tokenizer.tokens(); tok; tok = tok->next()) { len = len + 1U + tok->str().size(); if (len > pos1) { loc.setfile(tokenizer.list.getFiles().at(tok->fileIndex())); loc.line = tok->linenr(); break; } } const std::list<ErrorLogger::ErrorMessage::FileLocation> callStack(1, loc); // Create error message std::string summary; if (rule.summary.empty()) summary = "found '" + str.substr(pos1, pos2 - pos1) + "'"; else summary = rule.summary; const ErrorLogger::ErrorMessage errmsg(callStack, Severity::fromString(rule.severity), summary, rule.id, false); // Report error reportErr(errmsg); } pcre_free(re); } #endif }