diff --git a/cli/cmdlineparser.cpp b/cli/cmdlineparser.cpp index d152fa3c4..146614028 100644 --- a/cli/cmdlineparser.cpp +++ b/cli/cmdlineparser.cpp @@ -481,7 +481,7 @@ bool CmdLineParser::ParseFromArgs(int argc, const char* const argv[]) } // experimental --project else if (std::strncmp(argv[i], "--project=", 10) == 0) { - _settings.project(argv[i]+10); + _settings->importProject(argv[i]+10); } // Report progress @@ -765,7 +765,7 @@ bool CmdLineParser::ParseFromArgs(int argc, const char* const argv[]) } // Print error only if we have "real" command and expect files - if (!_exitAfterPrint && _pathnames.empty()) { + if (!_exitAfterPrint && _pathnames.empty() && _settings->fileSettings.empty()) { PrintMessage("cppcheck: No C or C++ source files found."); return false; } diff --git a/cli/cppcheckexecutor.cpp b/cli/cppcheckexecutor.cpp index 3867bcf50..9334a1d0e 100644 --- a/cli/cppcheckexecutor.cpp +++ b/cli/cppcheckexecutor.cpp @@ -154,7 +154,7 @@ bool CppCheckExecutor::parseFromArgs(CppCheck *cppcheck, int argc, const char* c FileLister::recursiveAddFiles(_files, Path::toNativeSeparators(*iter), _settings->library.markupExtensions(), matcher); } - if (_files.empty()) { + if (_files.empty() && settings.fileSettings.empty()) { std::cout << "cppcheck: error: could not find or open any of the paths given." << std::endl; if (!ignored.empty()) std::cout << "cppcheck: Maybe all paths were ignored?" << std::endl; diff --git a/lib/settings.cpp b/lib/settings.cpp index 5901f49d8..53486dc83 100644 --- a/lib/settings.cpp +++ b/lib/settings.cpp @@ -20,6 +20,8 @@ #include "preprocessor.h" // Preprocessor #include "utils.h" #include "tinyxml2.h" +#include "path.h" +#include "tokenlist.h" #include #include @@ -321,3 +323,58 @@ bool Settings::platformFile(const std::string &filename) return true; } + +void Settings::importProject(const std::string &filename) { + std::ifstream fin(filename); + if (!fin.is_open()) + return; + if (filename == "compile_commands.json") { + importCompileCommands(fin); + } +} + +void Settings::importCompileCommands(std::istream &istr) { + std::map values; + + TokenList tokenList(this); + tokenList.createTokens(istr); + for (const Token *tok = tokenList.front(); tok; tok = tok->next()) { + if (Token::Match(tok, "%str% : %str% [,}]")) { + std::string key = tok->str(); + std::string value = tok->strAt(2); + values[key.substr(1, key.size() - 2U)] = value.substr(1, value.size() - 2U); + } + + else if (tok->str() == "}") { + if (!values["file"].empty() && !values["command"].empty()) { + struct FileSettings fs; + fs.filename = Path::fromNativeSeparators(values["file"]); + std::string command = values["command"]; + std::string::size_type pos = 0; + while (std::string::npos != (pos = command.find(" ",pos))) { + pos++; + if (pos >= command.size()) + break; + if (command[pos] != '/' && command[pos] != '-') + continue; + pos++; + if (pos >= command.size()) + break; + char F = command[pos++]; + std::string fval; + while (pos < command.size() && command[pos] != ' ') + fval += command[pos++]; + if (F=='D') + fs.defines += fval + ";"; + else if (F=='U') + fs.undefs += fval + ";"; + else if (F=='I') + fs.includes += fval + ";"; + } + fileSettings.push_back(fs); + } + values.clear(); + } + } +} + diff --git a/lib/settings.h b/lib/settings.h index a406dff0b..dd6b43c7f 100644 --- a/lib/settings.h +++ b/lib/settings.h @@ -322,6 +322,19 @@ public: } return false; } + + /** File settings */ + struct FileSettings { + std::string filename; + std::string defines; + std::string undefs; + std::string includes; + }; + std::list fileSettings; + + void importProject(const std::string &filename); +private: + void importCompileCommands(std::istream &istr); }; /// @}