diff --git a/cli/cppcheckexecutor.cpp b/cli/cppcheckexecutor.cpp index 597efc7d9..b24ca64c7 100644 --- a/cli/cppcheckexecutor.cpp +++ b/cli/cppcheckexecutor.cpp @@ -94,7 +94,7 @@ bool CppCheckExecutor::parseFromArgs(CppCheck *cppcheck, int argc, const char* c // Execute recursiveAddFiles() to each given file parameter std::vector::const_iterator iter; for (iter = pathnames.begin(); iter != pathnames.end(); ++iter) - FileLister::recursiveAddFiles(_files, Path::toNativeSeparators(*iter)); + FileLister::recursiveAddFiles(_files, Path::toNativeSeparators(*iter), &_settings->library); } if (!_files.empty()) { @@ -176,11 +176,25 @@ int CppCheckExecutor::check(int argc, const char* const argv[]) std::size_t processedsize = 0; unsigned int c = 0; for (std::map::const_iterator i = _files.begin(); i != _files.end(); ++i) { - returnValue += cppCheck.check(i->first); - processedsize += i->second; - if (!settings._errorsOnly) - reportStatus(c + 1, _files.size(), processedsize, totalfilesize); - c++; + if (!_settings->library.acceptFile(i->first)) { + returnValue += cppCheck.check(i->first); + processedsize += i->second; + if (!settings._errorsOnly) + reportStatus(c + 1, _files.size(), processedsize, totalfilesize); + c++; + } + } + + // second loop to catch all library files which may not work until all + // c/cpp files have been parsed and checked + for (std::map::const_iterator i = _files.begin(); i != _files.end(); ++i) { + if (_settings->library.acceptFile(i->first)) { + returnValue += cppCheck.check(i->first); + processedsize += i->second; + if (!settings._errorsOnly) + reportStatus(c + 1, _files.size(), processedsize, totalfilesize); + c++; + } } cppCheck.checkFunctionUsage(); diff --git a/cli/filelister.cpp b/cli/filelister.cpp index d2de849a7..495cc8c68 100644 --- a/cli/filelister.cpp +++ b/cli/filelister.cpp @@ -21,6 +21,7 @@ #include #include #include +#include "library.h" #ifdef _WIN32 @@ -67,7 +68,7 @@ static BOOL MyFileExists(const std::string& path) return result; } -void FileLister::recursiveAddFiles(std::map &files, const std::string &path) +void FileLister::recursiveAddFiles(std::map &files, const std::string &path, const Library * library) { const std::string cleanedPath = Path::toNativeSeparators(path); @@ -123,7 +124,7 @@ void FileLister::recursiveAddFiles(std::map &files, co // File const std::string nativename = Path::fromNativeSeparators(fname); - if (!checkAllFilesInDir || Path::acceptFile(fname)) { + if (!checkAllFilesInDir || Path::acceptFile(fname, library)) { // Limitation: file sizes are assumed to fit in a 'size_t' #ifdef _WIN64 files[nativename] = (static_cast(ffd.nFileSizeHigh) << 32) | ffd.nFileSizeLow; @@ -133,7 +134,7 @@ void FileLister::recursiveAddFiles(std::map &files, co } } else { // Directory - FileLister::recursiveAddFiles(files, fname); + FileLister::recursiveAddFiles(files, fname, library); } } while (FindNextFileA(hFind, &ffd) != FALSE); @@ -187,7 +188,8 @@ std::string FileLister::getAbsolutePath(const std::string& path) void FileLister::recursiveAddFiles2(std::set &seen_paths, std::map &files, - const std::string &path) + const std::string &path, + const Library * library) { std::ostringstream oss; oss << path; @@ -213,7 +215,7 @@ void FileLister::recursiveAddFiles2(std::set &seen_paths, if (filename[filename.length()-1] != '/') { // File - if (Path::sameFileName(path,filename) || Path::acceptFile(filename)) { + if (Path::sameFileName(path,filename) || Path::acceptFile(filename, library)) { seen_paths.insert(absolute_path); struct stat sb; @@ -227,17 +229,17 @@ void FileLister::recursiveAddFiles2(std::set &seen_paths, // Directory seen_paths.insert(absolute_path); - recursiveAddFiles2(seen_paths, files, filename); + recursiveAddFiles2(seen_paths, files, filename, library); } } globfree(&glob_results); } -void FileLister::recursiveAddFiles(std::map &files, const std::string &path) +void FileLister::recursiveAddFiles(std::map &files, const std::string &path, const Library * library) { std::set seen_paths; - recursiveAddFiles2(seen_paths, files, path); + recursiveAddFiles2(seen_paths, files, path, library); } bool FileLister::isDirectory(const std::string &path) diff --git a/cli/filelister.h b/cli/filelister.h index 99940a20a..1e3847930 100644 --- a/cli/filelister.h +++ b/cli/filelister.h @@ -37,7 +37,7 @@ public: * @param files output map that associates the size of each file with its name * @param path root path */ - static void recursiveAddFiles(std::map &files, const std::string &path); + static void recursiveAddFiles(std::map &files, const std::string &path, const class Library * library); /** * @brief Is given path a directory? @@ -56,7 +56,8 @@ public: static void recursiveAddFiles2(std::set &seen_paths, std::map &files, - const std::string &path); + const std::string &path, + const class Library * library); #endif }; diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp index 8ac210ce5..42ba9f934 100644 --- a/lib/checkclass.cpp +++ b/lib/checkclass.cpp @@ -2016,6 +2016,15 @@ const std::list & CheckClass::callsPureVirtualFunction(const Func (tok->previous() && tok->previous()->str()==".")) continue; + if (tok->previous() && + tok->previous()->str()=="(") { + const Token * prev = tok->previous(); + if (prev->previous() && + (_settings->library.ignorefunction(tok->str()) + || _settings->library.ignorefunction(prev->previous()->str()))) + continue; + } + if (isPureWithoutBody(*callFunction)) { pureFunctionCalls.push_back(tok); continue; diff --git a/lib/checkunusedfunctions.cpp b/lib/checkunusedfunctions.cpp index f8220413d..9c93a6ea1 100644 --- a/lib/checkunusedfunctions.cpp +++ b/lib/checkunusedfunctions.cpp @@ -31,7 +31,7 @@ // FUNCTION USAGE - Check for unused functions etc //--------------------------------------------------------------------------- -void CheckUnusedFunctions::parseTokens(const Tokenizer &tokenizer) +void CheckUnusedFunctions::parseTokens(const Tokenizer &tokenizer, const char FileName[], const Settings *settings) { // Function declarations.. for (const Token *tok = tokenizer.tokens(); tok; tok = tok->next()) { @@ -96,6 +96,78 @@ void CheckUnusedFunctions::parseTokens(const Tokenizer &tokenizer) // 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 * qmlVarToken = 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 (qmlVarToken->str() == settings->library.blockstart(FileName)) { + scope++; + } else if (qmlVarToken->str() == settings->library.blockend(FileName)) + scope--; + else if (qmlVarToken->next()->str() == "(" && + (!settings->library.iskeyword(FileName, qmlVarToken->str()))) { + if (_functions.find(qmlVarToken->str()) != _functions.end()) + _functions[qmlVarToken->str()].usedOtherFile = true; + } + qmlVarToken = qmlVarToken->next(); + } + } + + if (!settings->library.acceptFile(FileName) // only check c/c++ + && 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.acceptFile(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; diff --git a/lib/checkunusedfunctions.h b/lib/checkunusedfunctions.h index d9b95297b..367705e4b 100644 --- a/lib/checkunusedfunctions.h +++ b/lib/checkunusedfunctions.h @@ -44,7 +44,7 @@ public: // Parse current tokens and determine.. // * Check what functions are used // * What functions are declared - void parseTokens(const Tokenizer &tokenizer); + void parseTokens(const Tokenizer &tokenizer, const char FileName[], const Settings *settings); void check(ErrorLogger * const errorLogger); diff --git a/lib/cppcheck.cpp b/lib/cppcheck.cpp index 9d7da8ec9..b3abcc077 100644 --- a/lib/cppcheck.cpp +++ b/lib/cppcheck.cpp @@ -131,7 +131,7 @@ unsigned int CppCheck::processFile(const std::string& filename, const std::strin exitcode = 0; // only show debug warnings for accepted C/C++ source files - if (!Path::acceptFile(filename)) + if (!Path::acceptFile(filename, &_settings.library)) _settings.debugwarnings = false; if (_settings.terminated()) @@ -368,7 +368,7 @@ void CppCheck::checkFile(const std::string &code, const char FileName[]) } if (_settings.isEnabled("unusedFunction") && _settings._jobs == 1) - _checkUnusedFunctions.parseTokens(_tokenizer); + _checkUnusedFunctions.parseTokens(_tokenizer, FileName, &_settings); executeRules("normal", _tokenizer); @@ -557,6 +557,9 @@ void CppCheck::tooManyConfigsError(const std::string &file, const std::size_t nu void CppCheck::reportErr(const ErrorLogger::ErrorMessage &msg) { + if (!_settings.library.reportErrors(msg.file0)) + return; + std::string errmsg = msg.toString(_settings._verbose); if (errmsg.empty()) return; diff --git a/lib/library.cpp b/lib/library.cpp index 761fe3909..3d0b74d25 100644 --- a/lib/library.cpp +++ b/lib/library.cpp @@ -35,7 +35,14 @@ Library::Library(const Library &lib) : allocid(lib.allocid), _alloc(lib._alloc), _dealloc(lib._dealloc), - _noreturn(lib._noreturn) + _noreturn(lib._noreturn), + _ignorefunction(lib._ignorefunction), + _reporterrors(lib._reporterrors), + _fileextensions(lib._fileextensions), + _keywords(lib._keywords), + _executableblocks(lib._executableblocks), + _importers(lib._importers), + _reflection(lib._reflection) { } @@ -117,7 +124,7 @@ bool Library::load(const char exename[], const char path[]) _noreturn[name] = (strcmp(functionnode->GetText(), "true") == 0); else if (strcmp(functionnode->Name(),"leak-ignore")==0) leakignore.insert(name); - else if (strcmp(functionnode->Name(),"arg")==0 && functionnode->Attribute("nr") != NULL) { + else if (strcmp(functionnode->Name(), "arg") == 0 && functionnode->Attribute("nr") != NULL) { const int nr = atoi(functionnode->Attribute("nr")); bool notnull = false; bool notuninit = false; @@ -139,9 +146,140 @@ bool Library::load(const char exename[], const char path[]) argumentChecks[name][nr].notuninit = notuninit; argumentChecks[name][nr].formatstr = formatstr; argumentChecks[name][nr].strz = strz; + } else if (strcmp(functionnode->Name(), "ignorefunction") == 0) { + _ignorefunction[name] = (strcmp(functionnode->GetText(), "true") == 0); } else return false; } + } + + else if (strcmp(node->Name(),"files")==0) { + for (const tinyxml2::XMLElement *functionnode = node->FirstChildElement(); functionnode; functionnode = functionnode->NextSiblingElement()) { + if (strcmp(functionnode->Name(), "file") == 0) { + _fileextensions.push_back(functionnode->Attribute("ext")); + const char * report = functionnode->Attribute("reporterrors"); + if (report) + _reporterrors[functionnode->Attribute("ext")] = strcmp(report, "true")==0; + } else + return false; + } + } + + else if (strcmp(node->Name(), "keywords") == 0) { + for (const tinyxml2::XMLElement *functionnode = node->FirstChildElement(); functionnode; functionnode = functionnode->NextSiblingElement()) { + if (strcmp(functionnode->Name(), "library") == 0) { + const char * const extension = functionnode->Attribute("extension"); + if (_keywords.find(extension) == _keywords.end()) { + std::list list; + _keywords[extension] = list; + } + for (const tinyxml2::XMLElement *librarynode = functionnode->FirstChildElement(); librarynode; librarynode = librarynode->NextSiblingElement()) { + if (strcmp(librarynode->Name(), "keyword") == 0) { + _keywords.at(extension).push_back(librarynode->Attribute("name")); + } else + return false; + } + } else + return false; + } + } + + else if (strcmp(node->Name(), "exported") == 0) { + for (const tinyxml2::XMLElement *functionnode = node->FirstChildElement(); functionnode; functionnode = functionnode->NextSiblingElement()) { + if (strcmp(functionnode->Name(), "exporter") == 0) { + const char * prefix = (functionnode->Attribute("prefix")); + if (prefix) { + std::map::const_iterator + it = _exporters.find(prefix); + if (it == _exporters.end()) { + // add the missing list for later on + ExportedFunctions exporter; + _exporters[prefix] = exporter; + } + } else + return false; + + for (const tinyxml2::XMLElement *enode = functionnode->FirstChildElement(); enode; enode = enode->NextSiblingElement()) { + if (strcmp(enode->Name(), "prefix") == 0) { + _exporters[prefix].addPrefix(enode->Attribute("name")); + } else if (strcmp(enode->Name(), "suffix") == 0) { + _exporters[prefix].addSuffix(enode->Attribute("name")); + } else + return false; + } + } else + return false; + } + } + + else if (strcmp(node->Name(), "imported") == 0) { + for (const tinyxml2::XMLElement *functionnode = node->FirstChildElement(); functionnode; functionnode = functionnode->NextSiblingElement()) { + if (strcmp(functionnode->Name(), "library") == 0) { + const char * const extension = functionnode->Attribute("extension"); + if (_importers.find(extension) == _importers.end()) { + std::list list; + _importers[extension] = list; + } + for (const tinyxml2::XMLElement *librarynode = functionnode->FirstChildElement(); librarynode; librarynode = librarynode->NextSiblingElement()) { + if (strcmp(librarynode->Name(), "importer") == 0) { + _importers.at(extension).push_back(librarynode->Attribute("name")); + } else + return false; + } + } + } + } + + else if (strcmp(node->Name(), "reflection") == 0) { + for (const tinyxml2::XMLElement *functionnode = node->FirstChildElement(); functionnode; functionnode = functionnode->NextSiblingElement()) { + if (strcmp(functionnode->Name(), "library") == 0) { + const char * const extension = functionnode->Attribute("extension"); + if (_reflection.find(extension) == _reflection.end()) { + std::map map; + _reflection[extension] = map; + } + for (const tinyxml2::XMLElement *librarynode = functionnode->FirstChildElement(); librarynode; librarynode = librarynode->NextSiblingElement()) { + if (strcmp(librarynode->Name(), "call") == 0) { + const char * const argString = librarynode->Attribute("arg"); + if (argString) { + _reflection.at(extension)[librarynode->Attribute("name")] + = atoi(argString); + } + } else + return false; + } + } else + return false; + } + } + + else if (strcmp(node->Name(), "codeblocks") == 0) { + for (const tinyxml2::XMLElement *functionnode = node->FirstChildElement(); functionnode; functionnode = functionnode->NextSiblingElement()) { + if (strcmp(functionnode->Name(), "library") == 0) { + const char * const extension = functionnode->Attribute("extension"); + if (_executableblocks.find(extension) == _executableblocks.end()) { + CodeBlock blockInfo; + _executableblocks[extension] = blockInfo; + } + for (const tinyxml2::XMLElement *librarynode = functionnode->FirstChildElement(); librarynode; librarynode = librarynode->NextSiblingElement()) { + if (strcmp(librarynode->Name(), "block") == 0) { + _executableblocks.at(extension).addBlock(librarynode->Attribute("name")); + } else if (strcmp(librarynode->Name(), "structure") == 0) { + const char * start = librarynode->Attribute("start"); + if (start) + _executableblocks.at(extension).setStart(start); + const char * end = librarynode->Attribute("end"); + if (end) + _executableblocks.at(extension).setEnd(end); + const char * offset = librarynode->Attribute("offset"); + if (offset) + _executableblocks.at(extension).setOffset(atoi(offset)); + } else + return false; + } + } + } + } else return false; } diff --git a/lib/library.h b/lib/library.h index 548662bb4..21a1f84ba 100644 --- a/lib/library.h +++ b/lib/library.h @@ -25,6 +25,10 @@ #include #include #include +#include +#include + +#include "path.h" /// @addtogroup Core /// @{ @@ -38,7 +42,7 @@ public: Library(const Library &); ~Library(); - bool load(const char exename[], const char path[]); + bool load(const char exename [], const char path []); /** get allocation id for function (by name) */ int alloc(const std::string &name) const { @@ -78,12 +82,12 @@ public: std::set leakignore; bool isnoreturn(const std::string &name) const { - std::map::const_iterator it = _noreturn.find(name); + std::map::const_iterator it = _noreturn.find(name); return (it != _noreturn.end() && it->second); } bool isnotnoreturn(const std::string &name) const { - std::map::const_iterator it = _noreturn.find(name); + std::map::const_iterator it = _noreturn.find(name); return (it != _noreturn.end() && !it->second); } @@ -102,32 +106,248 @@ public: std::map > argumentChecks; bool isnullargbad(const std::string &functionName, int argnr) const { - const ArgumentChecks *arg = getarg(functionName,argnr); + const ArgumentChecks *arg = getarg(functionName, argnr); return arg && arg->notnull; } bool isuninitargbad(const std::string &functionName, int argnr) const { - const ArgumentChecks *arg = getarg(functionName,argnr); + const ArgumentChecks *arg = getarg(functionName, argnr); return arg && arg->notuninit; } bool isargformatstr(const std::string &functionName, int argnr) const { - const ArgumentChecks *arg = getarg(functionName,argnr); + const ArgumentChecks *arg = getarg(functionName, argnr); return arg && arg->formatstr; } bool isargstrz(const std::string &functionName, int argnr) const { - const ArgumentChecks *arg = getarg(functionName,argnr); + const ArgumentChecks *arg = getarg(functionName, argnr); return arg && arg->strz; } + bool acceptFile(const std::string &path) const { + const std::string extension = Path::getFilenameExtensionInLowerCase(path); + const std::list::const_iterator it = + std::find(_fileextensions.begin(), _fileextensions.end(), extension); + return it != _fileextensions.end(); + } + + bool reportErrors(const std::string &path) const { + const std::map::const_iterator it = + _reporterrors.find(Path::getFilenameExtensionInLowerCase(path)); + if (it != _reporterrors.end()) { + return it->second; + } + // assume true if we don't know as it'll be a core-type (c/cpp etc) + return true; + } + + bool ignorefunction(const std::string &function) const { + const std::map::const_iterator it = _ignorefunction.find(function); + return (it != _ignorefunction.end() && it->second); + } + + bool isexecutableblock(const std::string &file, const std::string &token) const { + bool isexecblock; + const std::map::const_iterator map_it + = _executableblocks.find(Path::getFilenameExtensionInLowerCase(file)); + + if (map_it != _executableblocks.end()) { + isexecblock = map_it->second.isBlock(token); + } else { + isexecblock = false; + } + return isexecblock; + } + + int blockstartoffset(const std::string &file) const { + int offset = -1; + const std::map::const_iterator map_it + = _executableblocks.find(Path::getFilenameExtensionInLowerCase(file)); + + if (map_it != _executableblocks.end()) { + offset = map_it->second.offset(); + } + return offset; + } + + std::string blockstart(const std::string &file) const { + std::string start; + const std::map::const_iterator map_it + = _executableblocks.find(Path::getFilenameExtensionInLowerCase(file)); + + if (map_it != _executableblocks.end()) { + start = map_it->second.start(); + } + return start; + } + + std::string blockend(const std::string &file) const { + std::string end; + const std::map::const_iterator map_it + = _executableblocks.find(Path::getFilenameExtensionInLowerCase(file)); + + if (map_it != _executableblocks.end()) { + end = map_it->second.end(); + } + return end; + } + + bool iskeyword(const std::string &file, const std::string &keyword) const { + bool iskw; + const std::map >::const_iterator it = + _keywords.find(Path::getFilenameExtensionInLowerCase(file)); + + if (it != _keywords.end()) { + const std::list list = it->second; + const std::list::const_iterator list_it = + std::find(list.begin(), list.end(), keyword); + iskw = list_it != list.end(); + } else { + iskw = false; + } + return iskw; + } + + bool isexporter(const std::string &prefix) const { + const std::map::const_iterator it = + _exporters.find(prefix); + return it != _exporters.end(); + } + + bool isexportedprefix(const std::string &prefix, const std::string &token) const { + const std::map::const_iterator it = _exporters.find(prefix); + std::list::const_iterator token_it; + if (it != _exporters.end()) { + return it->second.isPrefix(token); + } else + return false; + } + + bool isexportedsuffix(const std::string &prefix, const std::string &token) const { + const std::map::const_iterator it = _exporters.find(prefix); + std::list::const_iterator token_it; + if (it != _exporters.end()) { + return it->second.isSuffix(token); + } else + return false; + } + + bool isimporter(const std::string& file, const std::string &importer) const { + bool isImporter; + const std::map >::const_iterator it = + _importers.find(Path::getFilenameExtensionInLowerCase(file)); + + if (it != _importers.end()) { + const std::list list = it->second; + const std::list::const_iterator it2 = + std::find(list.begin(), list.end(), importer); + isImporter = (it2 != list.end()); + } else { + isImporter = false; + } + return isImporter; + } + + bool isreflection(const std::string& file, const std::string &token) const { + bool isReflecMethod; + const std::map >::const_iterator it + = _reflection.find(Path::getFilenameExtensionInLowerCase(file)); + if (it != _reflection.end()) { + const std::map::const_iterator it2 = + it->second.find(token); + isReflecMethod = it2 != it->second.end(); + } else { + isReflecMethod = false; + } + return isReflecMethod; + } + + int reflectionArgument(const std::string& file, const std::string &token) const { + int argIndex = -1; + const std::map >::const_iterator it + = _reflection.find(Path::getFilenameExtensionInLowerCase(file)); + if (it != _reflection.end()) { + const std::map::const_iterator it2 = + it->second.find(token); + if (it2 != it->second.end()) { + argIndex = it2->second; + } + } + return argIndex; + } + std::set returnuninitdata; private: + class ExportedFunctions { + public: + void addPrefix(const std::string& prefix) { + _prefixes.push_back(prefix); + } + void addSuffix(const std::string& suffix) { + _suffixes.push_back(suffix); + } + bool isPrefix(const std::string& prefix) const { + return std::find(_prefixes.begin(), _prefixes.end(), prefix) + != _prefixes.end(); + } + bool isSuffix(const std::string& suffix) const { + return std::find(_suffixes.begin(), _suffixes.end(), suffix) + != _suffixes.end(); + } + + private: + std::list _prefixes; + std::list _suffixes; + }; + class CodeBlock { + public: + void setStart(const std::string& s) { + _start = s; + } + void setEnd(const std::string& e) { + _end = e; + } + void setOffset(const int o) { + _offset = o; + } + void addBlock(const std::string& blockName) { + _blocks.push_back(blockName); + } + std::string start() const { + return _start; + } + std::string end() const { + return _end; + } + int offset() const { + return _offset; + } + bool isBlock(const std::string& blockName) const { + return std::find(_blocks.begin(), _blocks.end(), blockName) + != _blocks.end(); + } + + private: + std::string _start; + std::string _end; + int _offset; + std::list _blocks; + }; int allocid; std::map _alloc; // allocation functions std::map _dealloc; // deallocation functions std::map _noreturn; // is function noreturn? + std::map _ignorefunction; // ignore functions/macros from a library (gtk, qt etc) + std::map _reporterrors; + std::list _fileextensions; // accepted file extensions + std::map > _keywords; // keywords for code in the library + std::map _executableblocks; // keywords for blocks of executable code + std::map _exporters; // keywords that export variables/functions to libraries (meta-code/macros) + std::map > _importers; // keywords that import variables/functions + std::map > _reflection; // invokation of reflection + const ArgumentChecks * getarg(const std::string &functionName, int argnr) const { std::map >::const_iterator it1; diff --git a/lib/path.cpp b/lib/path.cpp index 1c2ebc8ed..c8a3decff 100644 --- a/lib/path.cpp +++ b/lib/path.cpp @@ -22,6 +22,7 @@ #include #include #include "path.h" +#include "library.h" /** Is the filesystem case insensitive? */ static bool caseInsensitiveFilesystem() @@ -206,9 +207,9 @@ bool Path::isCPP(const std::string &path) return (getFilenameExtension(path) == ".C"); } -bool Path::acceptFile(const std::string &path) +bool Path::acceptFile(const std::string &path, const class Library *library) { - return !Path::isHeader(path) && (Path::isCPP(path) || Path::isC(path)); + return !Path::isHeader(path) && (Path::isCPP(path) || Path::isC(path) || (library ? library->acceptFile(path) : false)); } bool Path::isHeader(const std::string &path) diff --git a/lib/path.h b/lib/path.h index affd6b932..e35127fda 100644 --- a/lib/path.h +++ b/lib/path.h @@ -109,7 +109,7 @@ public: * @param filename filename to check. path info is optional * @return returns true if the file extension indicates it should be checked */ - static bool acceptFile(const std::string &filename); + static bool acceptFile(const std::string &filename, const class Library *library = 0); /** * @brief Identify language based on file extension. diff --git a/test/testfilelister.cpp b/test/testfilelister.cpp index 2767f6658..9b1665433 100644 --- a/test/testfilelister.cpp +++ b/test/testfilelister.cpp @@ -18,6 +18,7 @@ #include "testsuite.h" #include "filelister.h" +#include "settings.h" #include #ifndef _WIN32 @@ -75,7 +76,8 @@ private: void recursiveAddFiles() const { // Recursively add add files.. std::map files; - FileLister::recursiveAddFiles(files, "."); + Settings settings; // TODO(struscott): Pull in settings + FileLister::recursiveAddFiles(files, ".", &settings.library); // In case there are leading "./".. for (std::map::iterator i = files.begin(); i != files.end();) { diff --git a/test/testunusedfunctions.cpp b/test/testunusedfunctions.cpp index a02653492..a28fb1af2 100644 --- a/test/testunusedfunctions.cpp +++ b/test/testunusedfunctions.cpp @@ -71,7 +71,7 @@ private: // Check for unused functions.. CheckUnusedFunctions checkUnusedFunctions(&tokenizer, &settings, this); - checkUnusedFunctions.parseTokens(tokenizer); + checkUnusedFunctions.parseTokens(tokenizer, "someFile.c", &settings); checkUnusedFunctions.check(this); } @@ -262,7 +262,7 @@ private: std::istringstream istr(code); tokenizer.tokenize(istr, fname.str().c_str()); - c.parseTokens(tokenizer); + c.parseTokens(tokenizer, "someFile.c", &settings); } // Check for unused functions..