From 6d7dd7400df1c51a7a2b2f0a1ecc89c0b82156a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sun, 26 Apr 2020 10:20:56 +0200 Subject: [PATCH] Refactoring; Sort options alphabetically. Removed unused --check-diff functionality. --- cli/cmdlineparser.cpp | 1038 ++++++++++++++++++++--------------------- lib/exprengine.cpp | 17 - lib/settings.cpp | 48 +- lib/settings.h | 148 +++--- 4 files changed, 585 insertions(+), 666 deletions(-) diff --git a/cli/cmdlineparser.cpp b/cli/cmdlineparser.cpp index 8ef43ca2a..39142f3e2 100644 --- a/cli/cmdlineparser.cpp +++ b/cli/cmdlineparser.cpp @@ -124,294 +124,8 @@ bool CmdLineParser::parseFromArgs(int argc, const char* const argv[]) for (int i = 1; i < argc; i++) { if (argv[i][0] == '-') { - if (std::strcmp(argv[i], "--version") == 0) { - mShowVersion = true; - mExitAfterPrint = true; - return true; - } - - else if (std::strncmp(argv[i], "--addon=", 8) == 0) - mSettings->addons.emplace_back(argv[i]+8); - - else if (std::strncmp(argv[i],"--addon-python=", 15) == 0) - mSettings->addonPython.assign(argv[i]+15); - - else if (std::strcmp(argv[i], "--clang") == 0) - mSettings->clang = true; - - else if (std::strncmp(argv[i], "--cppcheck-build-dir=", 21) == 0) { - mSettings->buildDir = Path::fromNativeSeparators(argv[i] + 21); - if (endsWith(mSettings->buildDir, '/')) - mSettings->buildDir.erase(mSettings->buildDir.size() - 1U); - } - - // Flag used for various purposes during debugging - else if (std::strcmp(argv[i], "--debug-simplified") == 0) - mSettings->debugSimplified = true; - - // Show --debug output after the first simplifications - else if (std::strcmp(argv[i], "--debug") == 0 || - std::strcmp(argv[i], "--debug-normal") == 0) - mSettings->debugnormal = true; - - // Show debug warnings - else if (std::strcmp(argv[i], "--debug-warnings") == 0) - mSettings->debugwarnings = true; - - // Show template information - else if (std::strcmp(argv[i], "--debug-template") == 0) - mSettings->debugtemplate = true; - - // dump cppcheck data - else if (std::strcmp(argv[i], "--dump") == 0) - mSettings->dump = true; - - // max ctu depth - else if (std::strncmp(argv[i], "--max-ctu-depth=", 16) == 0) - mSettings->maxCtuDepth = std::atoi(argv[i] + 16); - - else if (std::strcmp(argv[i], "--experimental-fast") == 0) - // TODO: Remove this flag! - ; - - // (Experimental) exception handling inside cppcheck client - else if (std::strcmp(argv[i], "--exception-handling") == 0) - mSettings->exceptionHandling = true; - else if (std::strncmp(argv[i], "--exception-handling=", 21) == 0) { - mSettings->exceptionHandling = true; - const std::string exceptionOutfilename = &(argv[i][21]); - CppCheckExecutor::setExceptionOutput((exceptionOutfilename=="stderr") ? stderr : stdout); - } - - // Inconclusive checking - else if (std::strcmp(argv[i], "--inconclusive") == 0) - mSettings->inconclusive = true; - - // A --bug-hunting flag is needed by the tests - else if (std::strcmp(argv[i], "--bug-hunting") == 0) - mSettings->bugHunting = true; - - /* - else if (std::strncmp(argv[i], "--check-diff=", 13) == 0) { - std::ifstream fin(argv[i] + 13); - if (!fin.is_open()) { - printMessage("cppcheck: could not open file " + std::string(argv[i] + 13) + "."); - return false; - } - - mSettings->checkDiff = Settings::loadDiffFile(fin); - - for (const auto &diff: mSettings->bugHuntingDiff) { - if (!Path::acceptFile(diff.filename)) - continue; - const std::string filename = Path::fromNativeSeparators(diff.filename); - if (std::find(mPathNames.begin(), mPathNames.end(), filename) == mPathNames.end()) - mPathNames.push_back(filename); - } - } - */ - // Enforce language (--language=, -x) - else if (std::strncmp(argv[i], "--language=", 11) == 0 || std::strcmp(argv[i], "-x") == 0) { - std::string str; - if (argv[i][2]) { - str = argv[i]+11; - } else { - i++; - if (i >= argc || argv[i][0] == '-') { - printMessage("cppcheck: No language given to '-x' option."); - return false; - } - str = argv[i]; - } - - if (str == "c") - mSettings->enforcedLang = Settings::C; - else if (str == "c++") - mSettings->enforcedLang = Settings::CPP; - else { - printMessage("cppcheck: Unknown language '" + str + "' enforced."); - return false; - } - } - - // Filter errors - else if (std::strncmp(argv[i], "--exitcode-suppressions=", 24) == 0) { - // exitcode-suppressions=filename.txt - std::string filename = 24 + argv[i]; - - std::ifstream f(filename); - if (!f.is_open()) { - printMessage("cppcheck: Couldn't open the file: \"" + filename + "\"."); - return false; - } - const std::string errmsg(mSettings->nofail.parseFile(f)); - if (!errmsg.empty()) { - printMessage(errmsg); - return false; - } - } - - // Filter errors - else if (std::strncmp(argv[i], "--suppressions-list=", 20) == 0) { - std::string filename = argv[i]+20; - std::ifstream f(filename); - if (!f.is_open()) { - std::string message("cppcheck: Couldn't open the file: \""); - message += filename; - message += "\"."; - if (std::count(filename.begin(), filename.end(), ',') > 0 || - std::count(filename.begin(), filename.end(), '.') > 1) { - // If user tried to pass multiple files (we can only guess that) - // e.g. like this: --suppressions-list=a.txt,b.txt - // print more detailed error message to tell user how he can solve the problem - message += "\nIf you want to pass two files, you can do it e.g. like this:"; - message += "\n cppcheck --suppressions-list=a.txt --suppressions-list=b.txt file.cpp"; - } - - printMessage(message); - return false; - } - const std::string errmsg(mSettings->nomsg.parseFile(f)); - if (!errmsg.empty()) { - printMessage(errmsg); - return false; - } - } - - else if (std::strncmp(argv[i], "--suppress-xml=", 15) == 0) { - const char * filename = argv[i] + 15; - const std::string errmsg(mSettings->nomsg.parseXmlFile(filename)); - if (!errmsg.empty()) { - printMessage(errmsg); - return false; - } - } - - else if (std::strncmp(argv[i], "--suppress=", 11) == 0) { - const std::string suppression = argv[i]+11; - const std::string errmsg(mSettings->nomsg.addSuppressionLine(suppression)); - if (!errmsg.empty()) { - printMessage(errmsg); - return false; - } - } - - // Enables inline suppressions. - else if (std::strcmp(argv[i], "--inline-suppr") == 0) - mSettings->inlineSuppressions = true; - - // Verbose error messages (configuration info) - else if (std::strcmp(argv[i], "-v") == 0 || std::strcmp(argv[i], "--verbose") == 0) - mSettings->verbose = true; - - // Force checking of files that have "too many" configurations - else if (std::strcmp(argv[i], "-f") == 0 || std::strcmp(argv[i], "--force") == 0) - mSettings->force = true; - - // Output relative paths - else if (std::strcmp(argv[i], "-rp") == 0 || std::strcmp(argv[i], "--relative-paths") == 0) - mSettings->relativePaths = true; - else if (std::strncmp(argv[i], "-rp=", 4) == 0 || std::strncmp(argv[i], "--relative-paths=", 17) == 0) { - mSettings->relativePaths = true; - if (argv[i][argv[i][3]=='='?4:17] != 0) { - std::string paths = argv[i]+(argv[i][3]=='='?4:17); - for (;;) { - const std::string::size_type pos = paths.find(';'); - if (pos == std::string::npos) { - mSettings->basePaths.push_back(Path::fromNativeSeparators(paths)); - break; - } - mSettings->basePaths.push_back(Path::fromNativeSeparators(paths.substr(0, pos))); - paths.erase(0, pos + 1); - } - } else { - printMessage("cppcheck: No paths specified for the '" + std::string(argv[i]) + "' option."); - return false; - } - } - - // Write results in file - else if (std::strncmp(argv[i], "--output-file=", 14) == 0) - mSettings->outputFile = Path::simplifyPath(Path::fromNativeSeparators(argv[i] + 14)); - - // Write results in results.plist - else if (std::strncmp(argv[i], "--plist-output=", 15) == 0) { - mSettings->plistOutput = Path::simplifyPath(Path::fromNativeSeparators(argv[i] + 15)); - if (mSettings->plistOutput.empty()) - mSettings->plistOutput = "./"; - else if (!endsWith(mSettings->plistOutput,'/')) - mSettings->plistOutput += '/'; - } - - // Write results in results.xml - else if (std::strcmp(argv[i], "--xml") == 0) - mSettings->xml = true; - - // Define the XML file version (and enable XML output) - else if (std::strncmp(argv[i], "--xml-version=", 14) == 0) { - const std::string numberString(argv[i]+14); - - std::istringstream iss(numberString); - if (!(iss >> mSettings->xml_version)) { - printMessage("cppcheck: argument to '--xml-version' is not a number."); - return false; - } - - if (mSettings->xml_version != 2) { - // We only have xml version 2 - printMessage("cppcheck: '--xml-version' can only be 2."); - return false; - } - - // Enable also XML if version is set - mSettings->xml = true; - } - - // use a file filter - else if (std::strncmp(argv[i], "--file-filter=", 14) == 0) - mSettings->fileFilter = std::string(argv[i] + 14); - - // Only print something when there are errors - else if (std::strcmp(argv[i], "-q") == 0 || std::strcmp(argv[i], "--quiet") == 0) - mSettings->quiet = true; - - // Check configuration - else if (std::strcmp(argv[i], "--check-config") == 0) { - mSettings->checkConfiguration = true; - } - - // Check library definitions - else if (std::strcmp(argv[i], "--check-library") == 0) { - mSettings->checkLibrary = true; - } - - else if (std::strncmp(argv[i], "--enable=", 9) == 0) { - const std::string errmsg = mSettings->addEnabled(argv[i] + 9); - if (!errmsg.empty()) { - printMessage(errmsg); - return false; - } - // when "style" is enabled, also enable "warning", "performance" and "portability" - if (mSettings->isEnabled(Settings::STYLE)) { - mSettings->addEnabled("warning"); - mSettings->addEnabled("performance"); - mSettings->addEnabled("portability"); - } - } - - // --error-exitcode=1 - else if (std::strncmp(argv[i], "--error-exitcode=", 17) == 0) { - const std::string temp = argv[i]+17; - std::istringstream iss(temp); - if (!(iss >> mSettings->exitCode)) { - mSettings->exitCode = 0; - printMessage("cppcheck: Argument must be an integer. Try something like '--error-exitcode=1'."); - return false; - } - } - // User define - else if (std::strncmp(argv[i], "-D", 2) == 0) { + if (std::strncmp(argv[i], "-D", 2) == 0) { std::string define; // "-D define" @@ -439,27 +153,6 @@ bool CmdLineParser::parseFromArgs(int argc, const char* const argv[]) def = true; } - // User undef - else if (std::strncmp(argv[i], "-U", 2) == 0) { - std::string undef; - - // "-U undef" - if (std::strcmp(argv[i], "-U") == 0) { - ++i; - if (i >= argc || argv[i][0] == '-') { - printMessage("cppcheck: argument to '-U' is missing."); - return false; - } - - undef = argv[i]; - } - // "-Uundef" - else { - undef = 2 + argv[i]; - } - - mSettings->userUndefs.insert(undef); - } // -E else if (std::strcmp(argv[i], "-E") == 0) { @@ -493,24 +186,57 @@ bool CmdLineParser::parseFromArgs(int argc, const char* const argv[]) path += '/'; mSettings->includePaths.push_back(path); - } else if (std::strncmp(argv[i], "--include=", 10) == 0) { - std::string path = argv[i] + 10; + } - path = Path::fromNativeSeparators(path); + // User undef + else if (std::strncmp(argv[i], "-U", 2) == 0) { + std::string undef; - mSettings->userIncludes.push_back(path); - } else if (std::strncmp(argv[i], "--includes-file=", 16) == 0) { - // open this file and read every input file (1 file name per line) - const std::string includesFile(16 + argv[i]); - if (!addIncludePathsToList(includesFile, &mSettings->includePaths)) { - printMessage("Cppcheck: unable to open includes file at '" + includesFile + "'"); - return false; + // "-U undef" + if (std::strcmp(argv[i], "-U") == 0) { + ++i; + if (i >= argc || argv[i][0] == '-') { + printMessage("cppcheck: argument to '-U' is missing."); + return false; + } + + undef = argv[i]; } - } else if (std::strncmp(argv[i], "--config-exclude=",17) ==0) { + // "-Uundef" + else { + undef = 2 + argv[i]; + } + + mSettings->userUndefs.insert(undef); + } + + else if (std::strncmp(argv[i], "--addon=", 8) == 0) + mSettings->addons.emplace_back(argv[i]+8); + + else if (std::strncmp(argv[i],"--addon-python=", 15) == 0) + mSettings->addonPython.assign(argv[i]+15); + + else if (std::strcmp(argv[i], "--bug-hunting") == 0) + mSettings->bugHunting = true; + + // Check configuration + else if (std::strcmp(argv[i], "--check-config") == 0) + mSettings->checkConfiguration = true; + + // Check library definitions + else if (std::strcmp(argv[i], "--check-library") == 0) + mSettings->checkLibrary = true; + + else if (std::strcmp(argv[i], "--clang") == 0) + mSettings->clang = true; + + else if (std::strncmp(argv[i], "--config-exclude=",17) ==0) { std::string path = argv[i] + 17; path = Path::fromNativeSeparators(path); mSettings->configExcludePaths.insert(path); - } else if (std::strncmp(argv[i], "--config-excludes-file=", 23) == 0) { + } + + else if (std::strncmp(argv[i], "--config-excludes-file=", 23) == 0) { // open this file and read every input file (1 file name per line) const std::string cfgExcludesFile(23 + argv[i]); if (!addPathsToSet(cfgExcludesFile, &mSettings->configExcludePaths)) { @@ -519,10 +245,128 @@ bool CmdLineParser::parseFromArgs(int argc, const char* const argv[]) } } + else if (std::strncmp(argv[i], "--cppcheck-build-dir=", 21) == 0) { + mSettings->buildDir = Path::fromNativeSeparators(argv[i] + 21); + if (endsWith(mSettings->buildDir, '/')) + mSettings->buildDir.erase(mSettings->buildDir.size() - 1U); + } + + // Show --debug output after the first simplifications + else if (std::strcmp(argv[i], "--debug") == 0 || + std::strcmp(argv[i], "--debug-normal") == 0) + mSettings->debugnormal = true; + + // Flag used for various purposes during debugging + else if (std::strcmp(argv[i], "--debug-simplified") == 0) + mSettings->debugSimplified = true; + + // Show template information + else if (std::strcmp(argv[i], "--debug-template") == 0) + mSettings->debugtemplate = true; + + // Show debug warnings + else if (std::strcmp(argv[i], "--debug-warnings") == 0) + mSettings->debugwarnings = true; + + // documentation.. + else if (std::strcmp(argv[i], "--doc") == 0) { + std::ostringstream doc; + // Get documentation.. + for (const Check * it : Check::instances()) { + const std::string& name(it->name()); + const std::string info(it->classInfo()); + if (!name.empty() && !info.empty()) + doc << "## " << name << " ##\n" + << info << "\n"; + } + + std::cout << doc.str(); + mExitAfterPrint = true; + return true; + } + + // dump cppcheck data + else if (std::strcmp(argv[i], "--dump") == 0) + mSettings->dump = true; + + else if (std::strncmp(argv[i], "--enable=", 9) == 0) { + const std::string errmsg = mSettings->addEnabled(argv[i] + 9); + if (!errmsg.empty()) { + printMessage(errmsg); + return false; + } + // when "style" is enabled, also enable "warning", "performance" and "portability" + if (mSettings->isEnabled(Settings::STYLE)) { + mSettings->addEnabled("warning"); + mSettings->addEnabled("performance"); + mSettings->addEnabled("portability"); + } + } + + // print all possible error messages.. + else if (std::strcmp(argv[i], "--errorlist") == 0) { + mShowErrorMessages = true; + mSettings->xml = true; + mExitAfterPrint = true; + } + + // --error-exitcode=1 + else if (std::strncmp(argv[i], "--error-exitcode=", 17) == 0) { + const std::string temp = argv[i]+17; + std::istringstream iss(temp); + if (!(iss >> mSettings->exitCode)) { + mSettings->exitCode = 0; + printMessage("cppcheck: Argument must be an integer. Try something like '--error-exitcode=1'."); + return false; + } + } + + // Exception handling inside cppcheck client + else if (std::strcmp(argv[i], "--exception-handling") == 0) + mSettings->exceptionHandling = true; + + else if (std::strncmp(argv[i], "--exception-handling=", 21) == 0) { + mSettings->exceptionHandling = true; + const std::string exceptionOutfilename = &(argv[i][21]); + CppCheckExecutor::setExceptionOutput((exceptionOutfilename=="stderr") ? stderr : stdout); + } + + // Filter errors + else if (std::strncmp(argv[i], "--exitcode-suppressions=", 24) == 0) { + // exitcode-suppressions=filename.txt + std::string filename = 24 + argv[i]; + + std::ifstream f(filename); + if (!f.is_open()) { + printMessage("cppcheck: Couldn't open the file: \"" + filename + "\"."); + return false; + } + const std::string errmsg(mSettings->nofail.parseFile(f)); + if (!errmsg.empty()) { + printMessage(errmsg); + return false; + } + } + + // use a file filter + else if (std::strncmp(argv[i], "--file-filter=", 14) == 0) + mSettings->fileFilter = std::string(argv[i] + 14); + // file list specified - else if (std::strncmp(argv[i], "--file-list=", 12) == 0) { + else if (std::strncmp(argv[i], "--file-list=", 12) == 0) // open this file and read every input file (1 file name per line) addFilesToList(12 + argv[i], mPathNames); + + // Force checking of files that have "too many" configurations + else if (std::strcmp(argv[i], "-f") == 0 || std::strcmp(argv[i], "--force") == 0) + mSettings->force = true; + + // Print help + else if (std::strcmp(argv[i], "-h") == 0 || std::strcmp(argv[i], "--help") == 0) { + mPathNames.clear(); + mShowHelp = true; + mExitAfterPrint = true; + break; } // Ignored paths @@ -558,12 +402,179 @@ bool CmdLineParser::parseFromArgs(int argc, const char* const argv[]) } } + else if (std::strncmp(argv[i], "--include=", 10) == 0) { + std::string path = argv[i] + 10; + path = Path::fromNativeSeparators(path); + mSettings->userIncludes.push_back(path); + } + + else if (std::strncmp(argv[i], "--includes-file=", 16) == 0) { + // open this file and read every input file (1 file name per line) + const std::string includesFile(16 + argv[i]); + if (!addIncludePathsToList(includesFile, &mSettings->includePaths)) { + printMessage("Cppcheck: unable to open includes file at '" + includesFile + "'"); + return false; + } + } + + // Inconclusive checking + else if (std::strcmp(argv[i], "--inconclusive") == 0) + mSettings->inconclusive = true; + + // Enables inline suppressions. + else if (std::strcmp(argv[i], "--inline-suppr") == 0) + mSettings->inlineSuppressions = true; + + // Checking threads + else if (std::strncmp(argv[i], "-j", 2) == 0) { + std::string numberString; + + // "-j 3" + if (std::strcmp(argv[i], "-j") == 0) { + ++i; + if (i >= argc || argv[i][0] == '-') { + printMessage("cppcheck: argument to '-j' is missing."); + return false; + } + + numberString = argv[i]; + } + + // "-j3" + else + numberString = argv[i]+2; + + std::istringstream iss(numberString); + if (!(iss >> mSettings->jobs)) { + printMessage("cppcheck: argument to '-j' is not a number."); + return false; + } + + if (mSettings->jobs > 10000) { + // This limit is here just to catch typos. If someone has + // need for more jobs, this value should be increased. + printMessage("cppcheck: argument for '-j' is allowed to be 10000 at max."); + return false; + } + } + + else if (std::strncmp(argv[i], "-l", 2) == 0) { + std::string numberString; + + // "-l 3" + if (std::strcmp(argv[i], "-l") == 0) { + ++i; + if (i >= argc || argv[i][0] == '-') { + printMessage("cppcheck: argument to '-l' is missing."); + return false; + } + + numberString = argv[i]; + } + + // "-l3" + else + numberString = argv[i]+2; + + std::istringstream iss(numberString); + if (!(iss >> mSettings->loadAverage)) { + printMessage("cppcheck: argument to '-l' is not a number."); + return false; + } + } + + // Enforce language (--language=, -x) + else if (std::strncmp(argv[i], "--language=", 11) == 0 || std::strcmp(argv[i], "-x") == 0) { + std::string str; + if (argv[i][2]) { + str = argv[i]+11; + } else { + i++; + if (i >= argc || argv[i][0] == '-') { + printMessage("cppcheck: No language given to '-x' option."); + return false; + } + str = argv[i]; + } + + if (str == "c") + mSettings->enforcedLang = Settings::C; + else if (str == "c++") + mSettings->enforcedLang = Settings::CPP; + else { + printMessage("cppcheck: Unknown language '" + str + "' enforced."); + return false; + } + } + // --library else if (std::strncmp(argv[i], "--library=", 10) == 0) { std::string lib(argv[i] + 10); mSettings->libraries.push_back(lib); } + // Set maximum number of #ifdef configurations to check + else if (std::strncmp(argv[i], "--max-configs=", 14) == 0) { + mSettings->force = false; + + std::istringstream iss(14+argv[i]); + if (!(iss >> mSettings->maxConfigs)) { + printMessage("cppcheck: argument to '--max-configs=' is not a number."); + return false; + } + + if (mSettings->maxConfigs < 1) { + printMessage("cppcheck: argument to '--max-configs=' must be greater than 0."); + return false; + } + + maxconfigs = true; + } + + // max ctu depth + else if (std::strncmp(argv[i], "--max-ctu-depth=", 16) == 0) + mSettings->maxCtuDepth = std::atoi(argv[i] + 16); + + // Write results in file + else if (std::strncmp(argv[i], "--output-file=", 14) == 0) + mSettings->outputFile = Path::simplifyPath(Path::fromNativeSeparators(argv[i] + 14)); + + // Specify platform + else if (std::strncmp(argv[i], "--platform=", 11) == 0) { + const std::string platform(11+argv[i]); + + if (platform == "win32A") + mSettings->platform(Settings::Win32A); + else if (platform == "win32W") + mSettings->platform(Settings::Win32W); + else if (platform == "win64") + mSettings->platform(Settings::Win64); + else if (platform == "unix32") + mSettings->platform(Settings::Unix32); + else if (platform == "unix64") + mSettings->platform(Settings::Unix64); + else if (platform == "native") + mSettings->platform(Settings::Native); + else if (platform == "unspecified") + mSettings->platform(Settings::Unspecified); + else if (!mSettings->loadPlatformFile(argv[0], platform)) { + std::string message("cppcheck: error: unrecognized platform: \""); + message += platform; + message += "\"."; + printMessage(message); + return false; + } + } + + // Write results in results.plist + else if (std::strncmp(argv[i], "--plist-output=", 15) == 0) { + mSettings->plistOutput = Path::simplifyPath(Path::fromNativeSeparators(argv[i] + 15)); + if (mSettings->plistOutput.empty()) + mSettings->plistOutput = "./"; + else if (!endsWith(mSettings->plistOutput,'/')) + mSettings->plistOutput += '/'; + } + // --project else if (std::strncmp(argv[i], "--project=", 10) == 0) { mSettings->checkAllConfigurations = false; // Can be overridden with --max-configs or --force @@ -631,175 +642,37 @@ bool CmdLineParser::parseFromArgs(int argc, const char* const argv[]) mSettings->project.ignoreOtherConfigs(mVSConfig); } + // Only print something when there are errors + else if (std::strcmp(argv[i], "-q") == 0 || std::strcmp(argv[i], "--quiet") == 0) + mSettings->quiet = true; + + // Output relative paths + else if (std::strcmp(argv[i], "-rp") == 0 || std::strcmp(argv[i], "--relative-paths") == 0) + mSettings->relativePaths = true; + else if (std::strncmp(argv[i], "-rp=", 4) == 0 || std::strncmp(argv[i], "--relative-paths=", 17) == 0) { + mSettings->relativePaths = true; + if (argv[i][argv[i][3]=='='?4:17] != 0) { + std::string paths = argv[i]+(argv[i][3]=='='?4:17); + for (;;) { + const std::string::size_type pos = paths.find(';'); + if (pos == std::string::npos) { + mSettings->basePaths.push_back(Path::fromNativeSeparators(paths)); + break; + } + mSettings->basePaths.push_back(Path::fromNativeSeparators(paths.substr(0, pos))); + paths.erase(0, pos + 1); + } + } else { + printMessage("cppcheck: No paths specified for the '" + std::string(argv[i]) + "' option."); + return false; + } + } + // Report progress else if (std::strcmp(argv[i], "--report-progress") == 0) { mSettings->reportProgress = true; } - // --std - else if (std::strcmp(argv[i], "--std=posix") == 0) { - printMessage("cppcheck: Option --std=posix is deprecated and will be removed in 2.05."); - } else if (std::strcmp(argv[i], "--std=c89") == 0) { - mSettings->standards.c = Standards::C89; - } else if (std::strcmp(argv[i], "--std=c99") == 0) { - mSettings->standards.c = Standards::C99; - } else if (std::strcmp(argv[i], "--std=c11") == 0) { - mSettings->standards.c = Standards::C11; - } else if (std::strcmp(argv[i], "--std=c++03") == 0) { - mSettings->standards.cpp = Standards::CPP03; - } else if (std::strcmp(argv[i], "--std=c++11") == 0) { - mSettings->standards.cpp = Standards::CPP11; - } else if (std::strcmp(argv[i], "--std=c++14") == 0) { - mSettings->standards.cpp = Standards::CPP14; - } else if (std::strcmp(argv[i], "--std=c++17") == 0) { - mSettings->standards.cpp = Standards::CPP17; - } else if (std::strcmp(argv[i], "--std=c++20") == 0) { - mSettings->standards.cpp = Standards::CPP20; - } - - // Output formatter - else if (std::strcmp(argv[i], "--template") == 0 || - std::strncmp(argv[i], "--template=", 11) == 0) { - // "--template format" - if (argv[i][10] == '=') - mSettings->templateFormat = argv[i] + 11; - else if ((i+1) < argc && argv[i+1][0] != '-') { - ++i; - mSettings->templateFormat = argv[i]; - } else { - printMessage("cppcheck: argument to '--template' is missing."); - return false; - } - - if (mSettings->templateFormat == "gcc") { - mSettings->templateFormat = "{file}:{line}:{column}: warning: {message} [{id}]\\n{code}"; - mSettings->templateLocation = "{file}:{line}:{column}: note: {info}\\n{code}"; - } else if (mSettings->templateFormat == "daca2") { - mSettings->daca = true; - mSettings->templateFormat = "{file}:{line}:{column}: {severity}: {message} [{id}]"; - mSettings->templateLocation = "{file}:{line}:{column}: note: {info}"; - } else if (mSettings->templateFormat == "vs") - mSettings->templateFormat = "{file}({line}): {severity}: {message}"; - else if (mSettings->templateFormat == "edit") - mSettings->templateFormat = "{file} +{line}: {severity}: {message}"; - else if (mSettings->templateFormat == "cppcheck1") - mSettings->templateFormat = "{callstack}: ({severity}{inconclusive:, inconclusive}) {message}"; - } - - else if (std::strcmp(argv[i], "--template-location") == 0 || - std::strncmp(argv[i], "--template-location=", 20) == 0) { - // "--template-location format" - if (argv[i][19] == '=') - mSettings->templateLocation = argv[i] + 20; - else if ((i+1) < argc && argv[i+1][0] != '-') { - ++i; - mSettings->templateLocation = argv[i]; - } else { - printMessage("cppcheck: argument to '--template' is missing."); - return false; - } - } - - // Checking threads - else if (std::strncmp(argv[i], "-j", 2) == 0) { - std::string numberString; - - // "-j 3" - if (std::strcmp(argv[i], "-j") == 0) { - ++i; - if (i >= argc || argv[i][0] == '-') { - printMessage("cppcheck: argument to '-j' is missing."); - return false; - } - - numberString = argv[i]; - } - - // "-j3" - else - numberString = argv[i]+2; - - std::istringstream iss(numberString); - if (!(iss >> mSettings->jobs)) { - printMessage("cppcheck: argument to '-j' is not a number."); - return false; - } - - if (mSettings->jobs > 10000) { - // This limit is here just to catch typos. If someone has - // need for more jobs, this value should be increased. - printMessage("cppcheck: argument for '-j' is allowed to be 10000 at max."); - return false; - } - } else if (std::strncmp(argv[i], "-l", 2) == 0) { - std::string numberString; - - // "-l 3" - if (std::strcmp(argv[i], "-l") == 0) { - ++i; - if (i >= argc || argv[i][0] == '-') { - printMessage("cppcheck: argument to '-l' is missing."); - return false; - } - - numberString = argv[i]; - } - - // "-l3" - else - numberString = argv[i]+2; - - std::istringstream iss(numberString); - if (!(iss >> mSettings->loadAverage)) { - printMessage("cppcheck: argument to '-l' is not a number."); - return false; - } - } - - // print all possible error messages.. - else if (std::strcmp(argv[i], "--errorlist") == 0) { - mShowErrorMessages = true; - mSettings->xml = true; - mExitAfterPrint = true; - } - - // documentation.. - else if (std::strcmp(argv[i], "--doc") == 0) { - std::ostringstream doc; - // Get documentation.. - for (const Check * it : Check::instances()) { - const std::string& name(it->name()); - const std::string info(it->classInfo()); - if (!name.empty() && !info.empty()) - doc << "## " << name << " ##\n" - << info << "\n"; - } - - std::cout << doc.str(); - mExitAfterPrint = true; - return true; - } - - // show timing information.. - else if (std::strncmp(argv[i], "--showtime=", 11) == 0) { - const std::string showtimeMode = argv[i] + 11; - if (showtimeMode == "file") - mSettings->showtime = SHOWTIME_MODES::SHOWTIME_FILE; - else if (showtimeMode == "summary") - mSettings->showtime = SHOWTIME_MODES::SHOWTIME_SUMMARY; - else if (showtimeMode == "top5") - mSettings->showtime = SHOWTIME_MODES::SHOWTIME_TOP5; - else if (showtimeMode.empty()) - mSettings->showtime = SHOWTIME_MODES::SHOWTIME_NONE; - else { - std::string message("cppcheck: error: unrecognized showtime mode: \""); - message += showtimeMode; - message += "\". Supported modes: file, summary, top5."; - printMessage(message); - return false; - } - } - #ifdef HAVE_RULES // Rule given at command line else if (std::strncmp(argv[i], "--rule=", 7) == 0) { @@ -850,57 +723,166 @@ bool CmdLineParser::parseFromArgs(int argc, const char* const argv[]) } #endif - // Specify platform - else if (std::strncmp(argv[i], "--platform=", 11) == 0) { - const std::string platform(11+argv[i]); - - if (platform == "win32A") - mSettings->platform(Settings::Win32A); - else if (platform == "win32W") - mSettings->platform(Settings::Win32W); - else if (platform == "win64") - mSettings->platform(Settings::Win64); - else if (platform == "unix32") - mSettings->platform(Settings::Unix32); - else if (platform == "unix64") - mSettings->platform(Settings::Unix64); - else if (platform == "native") - mSettings->platform(Settings::Native); - else if (platform == "unspecified") - mSettings->platform(Settings::Unspecified); - else if (!mSettings->loadPlatformFile(argv[0], platform)) { - std::string message("cppcheck: error: unrecognized platform: \""); - message += platform; - message += "\"."; + // show timing information.. + else if (std::strncmp(argv[i], "--showtime=", 11) == 0) { + const std::string showtimeMode = argv[i] + 11; + if (showtimeMode == "file") + mSettings->showtime = SHOWTIME_MODES::SHOWTIME_FILE; + else if (showtimeMode == "summary") + mSettings->showtime = SHOWTIME_MODES::SHOWTIME_SUMMARY; + else if (showtimeMode == "top5") + mSettings->showtime = SHOWTIME_MODES::SHOWTIME_TOP5; + else if (showtimeMode.empty()) + mSettings->showtime = SHOWTIME_MODES::SHOWTIME_NONE; + else { + std::string message("cppcheck: error: unrecognized showtime mode: \""); + message += showtimeMode; + message += "\". Supported modes: file, summary, top5."; printMessage(message); return false; } } - // Set maximum number of #ifdef configurations to check - else if (std::strncmp(argv[i], "--max-configs=", 14) == 0) { - mSettings->force = false; - - std::istringstream iss(14+argv[i]); - if (!(iss >> mSettings->maxConfigs)) { - printMessage("cppcheck: argument to '--max-configs=' is not a number."); - return false; - } - - if (mSettings->maxConfigs < 1) { - printMessage("cppcheck: argument to '--max-configs=' must be greater than 0."); - return false; - } - - maxconfigs = true; + // --std + else if (std::strcmp(argv[i], "--std=posix") == 0) { + printMessage("cppcheck: Option --std=posix is deprecated and will be removed in 2.05."); + } else if (std::strcmp(argv[i], "--std=c89") == 0) { + mSettings->standards.c = Standards::C89; + } else if (std::strcmp(argv[i], "--std=c99") == 0) { + mSettings->standards.c = Standards::C99; + } else if (std::strcmp(argv[i], "--std=c11") == 0) { + mSettings->standards.c = Standards::C11; + } else if (std::strcmp(argv[i], "--std=c++03") == 0) { + mSettings->standards.cpp = Standards::CPP03; + } else if (std::strcmp(argv[i], "--std=c++11") == 0) { + mSettings->standards.cpp = Standards::CPP11; + } else if (std::strcmp(argv[i], "--std=c++14") == 0) { + mSettings->standards.cpp = Standards::CPP14; + } else if (std::strcmp(argv[i], "--std=c++17") == 0) { + mSettings->standards.cpp = Standards::CPP17; + } else if (std::strcmp(argv[i], "--std=c++20") == 0) { + mSettings->standards.cpp = Standards::CPP20; } - // Print help - else if (std::strcmp(argv[i], "-h") == 0 || std::strcmp(argv[i], "--help") == 0) { - mPathNames.clear(); - mShowHelp = true; + else if (std::strncmp(argv[i], "--suppress=", 11) == 0) { + const std::string suppression = argv[i]+11; + const std::string errmsg(mSettings->nomsg.addSuppressionLine(suppression)); + if (!errmsg.empty()) { + printMessage(errmsg); + return false; + } + } + + // Filter errors + else if (std::strncmp(argv[i], "--suppressions-list=", 20) == 0) { + std::string filename = argv[i]+20; + std::ifstream f(filename); + if (!f.is_open()) { + std::string message("cppcheck: Couldn't open the file: \""); + message += filename; + message += "\"."; + if (std::count(filename.begin(), filename.end(), ',') > 0 || + std::count(filename.begin(), filename.end(), '.') > 1) { + // If user tried to pass multiple files (we can only guess that) + // e.g. like this: --suppressions-list=a.txt,b.txt + // print more detailed error message to tell user how he can solve the problem + message += "\nIf you want to pass two files, you can do it e.g. like this:"; + message += "\n cppcheck --suppressions-list=a.txt --suppressions-list=b.txt file.cpp"; + } + + printMessage(message); + return false; + } + const std::string errmsg(mSettings->nomsg.parseFile(f)); + if (!errmsg.empty()) { + printMessage(errmsg); + return false; + } + } + + else if (std::strncmp(argv[i], "--suppress-xml=", 15) == 0) { + const char * filename = argv[i] + 15; + const std::string errmsg(mSettings->nomsg.parseXmlFile(filename)); + if (!errmsg.empty()) { + printMessage(errmsg); + return false; + } + } + + // Output formatter + else if (std::strcmp(argv[i], "--template") == 0 || + std::strncmp(argv[i], "--template=", 11) == 0) { + // "--template format" + if (argv[i][10] == '=') + mSettings->templateFormat = argv[i] + 11; + else if ((i+1) < argc && argv[i+1][0] != '-') { + ++i; + mSettings->templateFormat = argv[i]; + } else { + printMessage("cppcheck: argument to '--template' is missing."); + return false; + } + + if (mSettings->templateFormat == "gcc") { + mSettings->templateFormat = "{file}:{line}:{column}: warning: {message} [{id}]\\n{code}"; + mSettings->templateLocation = "{file}:{line}:{column}: note: {info}\\n{code}"; + } else if (mSettings->templateFormat == "daca2") { + mSettings->daca = true; + mSettings->templateFormat = "{file}:{line}:{column}: {severity}: {message} [{id}]"; + mSettings->templateLocation = "{file}:{line}:{column}: note: {info}"; + } else if (mSettings->templateFormat == "vs") + mSettings->templateFormat = "{file}({line}): {severity}: {message}"; + else if (mSettings->templateFormat == "edit") + mSettings->templateFormat = "{file} +{line}: {severity}: {message}"; + else if (mSettings->templateFormat == "cppcheck1") + mSettings->templateFormat = "{callstack}: ({severity}{inconclusive:, inconclusive}) {message}"; + } + + else if (std::strcmp(argv[i], "--template-location") == 0 || + std::strncmp(argv[i], "--template-location=", 20) == 0) { + // "--template-location format" + if (argv[i][19] == '=') + mSettings->templateLocation = argv[i] + 20; + else if ((i+1) < argc && argv[i+1][0] != '-') { + ++i; + mSettings->templateLocation = argv[i]; + } else { + printMessage("cppcheck: argument to '--template' is missing."); + return false; + } + } + + else if (std::strcmp(argv[i], "-v") == 0 || std::strcmp(argv[i], "--verbose") == 0) + mSettings->verbose = true; + + else if (std::strcmp(argv[i], "--version") == 0) { + mShowVersion = true; mExitAfterPrint = true; - break; + return true; + } + + // Write results in results.xml + else if (std::strcmp(argv[i], "--xml") == 0) + mSettings->xml = true; + + // Define the XML file version (and enable XML output) + else if (std::strncmp(argv[i], "--xml-version=", 14) == 0) { + const std::string numberString(argv[i]+14); + + std::istringstream iss(numberString); + if (!(iss >> mSettings->xml_version)) { + printMessage("cppcheck: argument to '--xml-version' is not a number."); + return false; + } + + if (mSettings->xml_version != 2) { + // We only have xml version 2 + printMessage("cppcheck: '--xml-version' can only be 2."); + return false; + } + + // Enable also XML if version is set + mSettings->xml = true; } else { diff --git a/lib/exprengine.cpp b/lib/exprengine.cpp index ffacc96ef..259ff5cec 100644 --- a/lib/exprengine.cpp +++ b/lib/exprengine.cpp @@ -1756,23 +1756,6 @@ void ExprEngine::executeFunction(const Scope *functionScope, const Tokenizer *to // TODO.. what about functions in headers? return; - if (!settings->checkDiff.empty()) { - const std::string filename = tokenizer->list.getFiles().at(functionScope->bodyStart->fileIndex()); - bool check = false; - for (const auto &diff: settings->checkDiff) { - if (diff.filename != filename) - continue; - if (diff.fromLine > functionScope->bodyEnd->linenr()) - continue; - if (diff.toLine < functionScope->bodyStart->linenr()) - continue; - check = true; - break; - } - if (!check) - return; - } - int symbolValueIndex = 0; TrackExecution trackExecution; Data data(&symbolValueIndex, tokenizer, settings, callbacks, &trackExecution); diff --git a/lib/settings.cpp b/lib/settings.cpp index 364392a47..736a6e2e5 100644 --- a/lib/settings.cpp +++ b/lib/settings.cpp @@ -31,17 +31,20 @@ const char Settings::SafeChecks::XmlExternalVariables[] = "external-variables"; Settings::Settings() : mEnabled(0), addonPython("python"), + bugHunting(false), + checkAllConfigurations(true), checkConfiguration(false), - checkLibrary(false), checkHeaders(true), + checkLibrary(false), checkUnusedTemplates(false), clang(false), clangTidy(false), daca(false), - debugSimplified(false), + debugBugHunting(false), debugnormal(false), - debugwarnings(false), + debugSimplified(false), debugtemplate(false), + debugwarnings(false), dump(false), enforcedLang(None), exceptionHandling(false), @@ -49,14 +52,11 @@ Settings::Settings() experimental(false), force(false), inconclusive(false), - bugHunting(false), - debugBugHunting(false), inlineSuppressions(false), jobs(1), jointSuppressionReport(false), loadAverage(0), maxConfigs(12), - checkAllConfigurations(true), maxCtuDepth(2), preprocessOnly(false), quiet(false), @@ -153,39 +153,3 @@ bool Settings::isEnabled(const ValueFlow::Value *value, bool inconclusiveCheck) return false; return true; } - -std::vector Settings::loadDiffFile(std::istream &istr) -{ - std::vector ret; - std::string line; - std::string filename; - while (std::getline(istr, line)) { - if (line.compare(0, 11, "diff --git ") == 0) { - std::string::size_type pos = line.rfind(" b/"); - if (pos == std::string::npos) - continue; - filename = line.substr(pos+3); - } - if (line.compare(0,4,"@@ -") == 0) { - std::string::size_type pos1 = line.find(" ",4); - if (pos1 == std::string::npos) - continue; - std::string::size_type pos2 = line.find(" ",pos1 + 1); - if (pos2 == std::string::npos || pos2 < pos1+3) - continue; - if (line[pos1+1] != '+') - continue; - std::string::size_type posComma = line.find(",", pos1); - if (posComma > pos2) - continue; - std::string line1 = line.substr(pos1 + 2, posComma - pos1 - 2); - std::string line2 = line.substr(posComma+1, pos2 - posComma - 1); - Diff diff; - diff.filename = filename; - diff.fromLine = std::atoi(line1.c_str()); - diff.toLine = std::atoi(line1.c_str()) + std::atoi(line2.c_str()); - ret.push_back(diff); - } - } - return ret; -} diff --git a/lib/settings.h b/lib/settings.h index 21e2f37db..929b2f2b0 100644 --- a/lib/settings.h +++ b/lib/settings.h @@ -79,11 +79,17 @@ public: /** @brief Paths used as base for conversion to relative paths. */ std::vector basePaths; + /** @brief Bug hunting */ + bool bugHunting; + + /** Filename for bug hunting report */ + std::string bugHuntingReport; + /** @brief --cppcheck-build-dir */ std::string buildDir; - /** @brief --file-filter for analyzing special files */ - std::string fileFilter; + /** @brief check all configurations (false if -D or --max-configs is used */ + bool checkAllConfigurations; /** Is the 'configuration checking' wanted? */ bool checkConfiguration; @@ -91,11 +97,17 @@ public: /** Check for incomplete info in library files? */ bool checkLibrary; + /** @brief List of selected Visual Studio configurations that should be checks */ + std::list checkVsConfigs; + /** * Check code in the headers, this is on by default but can * be turned off to save CPU */ bool checkHeaders; + /** @brief check unknown function return values */ + std::set checkUnknownFunctionReturn; + /** Check unused/uninstantiated templates */ bool checkUnusedTemplates; @@ -111,18 +123,21 @@ public: /** @brief Are we running from DACA script? */ bool daca; - /** @brief Is --debug-simplified given? */ - bool debugSimplified; + /** @brief Debug bug hunting */ + bool debugBugHunting; /** @brief Is --debug-normal given? */ bool debugnormal; - /** @brief Is --debug-warnings given? */ - bool debugwarnings; + /** @brief Is --debug-simplified given? */ + bool debugSimplified; /** @brief Is --debug-template given? */ bool debugtemplate; + /** @brief Is --debug-warnings given? */ + bool debugwarnings; + /** @brief Is --dump given? */ bool dump; std::string dumpFile; @@ -152,6 +167,9 @@ public: */ bool experimental; + /** @brief --file-filter for analyzing special files */ + std::string fileFilter; + /** @brief Force checking the files with "too many" configurations (--force). */ bool force; @@ -159,77 +177,9 @@ public: for finding include files inside source files. (-I) */ std::list includePaths; - /** @brief List of selected Visual Studio configurations that should be checks */ - std::list checkVsConfigs; - /** @brief Inconclusive checks */ bool inconclusive; - /** Do not only check how interface is used. Also check that interface is safe. */ - class CPPCHECKLIB SafeChecks { - public: - SafeChecks() : classes(false), externalFunctions(false), internalFunctions(false), externalVariables(false) {} - - static const char XmlRootName[]; - static const char XmlClasses[]; - static const char XmlExternalFunctions[]; - static const char XmlInternalFunctions[]; - static const char XmlExternalVariables[]; - - void clear() { - classes = externalFunctions = internalFunctions = externalVariables = false; - } - - /** - * Public interface of classes - * - public function parameters can have any value - * - public functions can be called in any order - * - public variables can have any value - */ - bool classes; - - /** - * External functions - * - external functions can be called in any order - * - function parameters can have any values - */ - bool externalFunctions; - - /** - * Experimental: assume that internal functions can be used in any way - * This is only available in the GUI. - */ - bool internalFunctions; - - /** - * Global variables that can be modified outside the TU. - * - Such variable can have "any" value - */ - bool externalVariables; - }; - - SafeChecks safeChecks; - - /** @brief Bug hunting */ - bool bugHunting; - - /** @brief Debug bug hunting */ - bool debugBugHunting; - - /** Filename for bug hunting report */ - std::string bugHuntingReport; - - /** @brief Check diff */ - struct Diff { - std::string filename; - int fromLine; - int toLine; - }; - std::vector checkDiff; - - /** @brief check unknown function return values */ - std::set checkUnknownFunctionReturn; - /** @brief Is --inline-suppr given? */ bool inlineSuppressions; @@ -255,9 +205,6 @@ public: Default is 12. (--max-configs=N) */ unsigned int maxConfigs; - /** @brief --check all configurations */ - bool checkAllConfigurations; - /** @brief --max-ctu-depth */ int maxCtuDepth; @@ -308,6 +255,51 @@ public: */ std::list rules; + /** Do not only check how interface is used. Also check that interface is safe. */ + class CPPCHECKLIB SafeChecks { + public: + SafeChecks() : classes(false), externalFunctions(false), internalFunctions(false), externalVariables(false) {} + + static const char XmlRootName[]; + static const char XmlClasses[]; + static const char XmlExternalFunctions[]; + static const char XmlInternalFunctions[]; + static const char XmlExternalVariables[]; + + void clear() { + classes = externalFunctions = internalFunctions = externalVariables = false; + } + + /** + * Public interface of classes + * - public function parameters can have any value + * - public functions can be called in any order + * - public variables can have any value + */ + bool classes; + + /** + * External functions + * - external functions can be called in any order + * - function parameters can have any values + */ + bool externalFunctions; + + /** + * Experimental: assume that internal functions can be used in any way + * This is only available in the GUI. + */ + bool internalFunctions; + + /** + * Global variables that can be modified outside the TU. + * - Such variable can have "any" value + */ + bool externalVariables; + }; + + SafeChecks safeChecks; + /** @brief show timing information (--showtime=file|summary|top5) */ SHOWTIME_MODES showtime; @@ -390,8 +382,6 @@ public: */ bool isEnabled(const ValueFlow::Value *value, bool inconclusiveCheck=false) const; - static std::vector loadDiffFile(std::istream &istr); - /** Is posix library specified? */ bool posix() const { return std::find(libraries.begin(), libraries.end(), "posix") != libraries.end();