Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions cli/cmdlineparser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1163,6 +1163,12 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a
mSettings.checkAllConfigurations = false; // Can be overridden with --max-configs or --force
std::string projectFile = argv[i]+10;
projectType = project.import(projectFile, &mSettings, &mSuppressions);

auto printImportErrors = [&]() {
for (const auto &error : project.errors)
mLogger.printError(error);
};

if (projectType == ImportProject::Type::CPPCHECK_GUI) {
for (const std::string &lib : project.guiProject.libraries)
mSettings.libraries.emplace_back(lib);
Expand Down Expand Up @@ -1191,14 +1197,17 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a
mSettings.libraries.emplace_back("windows");
}
if (projectType == ImportProject::Type::MISSING) {
printImportErrors();
mLogger.printError("failed to open project '" + projectFile + "'. The file does not exist.");
return Result::Fail;
}
if (projectType == ImportProject::Type::UNKNOWN) {
printImportErrors();
mLogger.printError("failed to load project '" + projectFile + "'. The format is unknown.");
return Result::Fail;
}
if (projectType == ImportProject::Type::FAILURE) {
printImportErrors();
mLogger.printError("failed to load project '" + projectFile + "'. An error occurred.");
return Result::Fail;
}
Expand Down
6 changes: 6 additions & 0 deletions gui/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1990,6 +1990,12 @@ void MainWindow::analyzeProject(const ProjectFile *projectFile, const QStringLis
break;
}

if (!p.errors.empty())
errorMessage += ": \n";

for (const auto &error : p.errors)
errorMessage += "\n - " + QString::fromStdString(error);

if (!errorMessage.isEmpty()) {
QMessageBox msg(QMessageBox::Critical,
tr("Cppcheck"),
Expand Down
52 changes: 24 additions & 28 deletions lib/importproject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@ bool ImportProject::importCompileCommands(std::istream &istr)
picojson::value compileCommands;
istr >> compileCommands;
if (!compileCommands.is<picojson::array>()) {
printError("compilation database is not a JSON array");
errors.emplace_back("compilation database is not a JSON array");
return false;
}

Expand All @@ -345,12 +345,12 @@ bool ImportProject::importCompileCommands(std::istream &istr)
picojson::object obj = fileInfo.get<picojson::object>();

if (obj.count("directory") == 0) {
printError("'directory' field in compilation database entry missing");
errors.emplace_back("'directory' field in compilation database entry missing");
return false;
}

if (!obj["directory"].is<std::string>()) {
printError("'directory' field in compilation database entry is not a string");
errors.emplace_back("'directory' field in compilation database entry is not a string");
return false;
}

Expand All @@ -377,24 +377,24 @@ bool ImportProject::importCompileCommands(std::istream &istr)
}
}
} else {
printError("'arguments' field in compilation database entry is not a JSON array");
errors.emplace_back("'arguments' field in compilation database entry is not a JSON array");
return false;
}
} else if (obj.count("command")) {
doUnescape = true;
if (obj["command"].is<std::string>()) {
command = obj["command"].get<std::string>();
} else {
printError("'command' field in compilation database entry is not a string");
errors.emplace_back("'command' field in compilation database entry is not a string");
return false;
}
} else {
printError("no 'arguments' or 'command' field found in compilation database entry");
errors.emplace_back("no 'arguments' or 'command' field found in compilation database entry");
return false;
}

if (!obj.count("file") || !obj["file"].is<std::string>()) {
printError("skip compilation database entry because it does not have a proper 'file' field");
errors.emplace_back("skip compilation database entry because it does not have a proper 'file' field");
continue;
}

Expand Down Expand Up @@ -434,14 +434,14 @@ bool ImportProject::importSln(std::istream &istr, const std::string &path, const
std::string line;

if (!std::getline(istr,line)) {
printError("Visual Studio solution file is empty");
errors.emplace_back("Visual Studio solution file is empty");
return false;
}

if (!startsWith(line, "Microsoft Visual Studio Solution File")) {
// Skip BOM
if (!std::getline(istr, line) || !startsWith(line, "Microsoft Visual Studio Solution File")) {
printError("Visual Studio solution file header not found");
errors.emplace_back("Visual Studio solution file header not found");
return false;
}
}
Expand All @@ -466,14 +466,14 @@ bool ImportProject::importSln(std::istream &istr, const std::string &path, const
vcxproj = path + vcxproj;
vcxproj = Path::fromNativeSeparators(std::move(vcxproj));
if (!importVcxproj(vcxproj, variables, "", fileFilters, sharedItemsProjects)) {
printError("failed to load '" + vcxproj + "' from Visual Studio solution");
errors.emplace_back("failed to load '" + vcxproj + "' from Visual Studio solution");
return false;
}
found = true;
}

if (!found) {
printError("no projects found in Visual Studio solution file");
errors.emplace_back("no projects found in Visual Studio solution file");
return false;
}

Expand Down Expand Up @@ -730,7 +730,7 @@ bool ImportProject::importVcxproj(const std::string &filename,
tinyxml2::XMLDocument doc;
const tinyxml2::XMLError error = doc.LoadFile(filename.c_str());
if (error != tinyxml2::XML_SUCCESS) {
printError(std::string("Visual Studio project file is not a valid XML - ") + tinyxml2::XMLDocument::ErrorIDToName(error));
errors.emplace_back(std::string("Visual Studio project file is not a valid XML - ") + tinyxml2::XMLDocument::ErrorIDToName(error));
return false;
}
return importVcxproj(filename, doc, variables, additionalIncludeDirectories, fileFilters, cache);
Expand All @@ -749,7 +749,7 @@ bool ImportProject::importVcxproj(const std::string &filename, const tinyxml2::X

const tinyxml2::XMLElement * const rootnode = doc.FirstChildElement();
if (rootnode == nullptr) {
printError("Visual Studio project file has no XML root node");
errors.emplace_back("Visual Studio project file has no XML root node");
return false;
}
for (const tinyxml2::XMLElement *node = rootnode->FirstChildElement(); node; node = node->NextSiblingElement()) {
Expand Down Expand Up @@ -810,13 +810,13 @@ bool ImportProject::importVcxproj(const std::string &filename, const tinyxml2::X
pathToSharedItemsFile = variables["ProjectDir"] + projectAttribute;
}
if (!simplifyPathWithVariables(pathToSharedItemsFile, variables)) {
printError("Could not simplify path to referenced shared items project");
errors.emplace_back("Could not simplify path to referenced shared items project");
return false;
}

SharedItemsProject toAdd = importVcxitems(pathToSharedItemsFile, fileFilters, cache);
if (!toAdd.successful) {
printError("Could not load shared items project \"" + pathToSharedItemsFile + "\" from original path \"" + std::string(projectAttribute) + "\".");
errors.emplace_back("Could not load shared items project \"" + pathToSharedItemsFile + "\" from original path \"" + std::string(projectAttribute) + "\".");
return false;
}
sharedItemsProjects.emplace_back(toAdd);
Expand Down Expand Up @@ -928,12 +928,12 @@ ImportProject::SharedItemsProject ImportProject::importVcxitems(const std::strin
tinyxml2::XMLDocument doc;
const tinyxml2::XMLError error = doc.LoadFile(filename.c_str());
if (error != tinyxml2::XML_SUCCESS) {
printError(std::string("Visual Studio project file is not a valid XML - ") + tinyxml2::XMLDocument::ErrorIDToName(error));
errors.emplace_back(std::string("Visual Studio project file is not a valid XML - ") + tinyxml2::XMLDocument::ErrorIDToName(error));
return result;
}
const tinyxml2::XMLElement * const rootnode = doc.FirstChildElement();
if (rootnode == nullptr) {
printError("Visual Studio project file has no XML root node");
errors.emplace_back("Visual Studio project file has no XML root node");
return result;
}
for (const tinyxml2::XMLElement *node = rootnode->FirstChildElement(); node; node = node->NextSiblingElement()) {
Expand All @@ -951,7 +951,7 @@ ImportProject::SharedItemsProject ImportProject::importVcxitems(const std::strin

result.sourceFiles.emplace_back(file);
} else {
printError("Could not find shared items source file");
errors.emplace_back("Could not find shared items source file");
return result;
}
}
Expand Down Expand Up @@ -979,12 +979,12 @@ bool ImportProject::importBcb6Prj(const std::string &projectFilename)
tinyxml2::XMLDocument doc;
const tinyxml2::XMLError error = doc.LoadFile(projectFilename.c_str());
if (error != tinyxml2::XML_SUCCESS) {
printError(std::string("Borland project file is not a valid XML - ") + tinyxml2::XMLDocument::ErrorIDToName(error));
errors.emplace_back(std::string("Borland project file is not a valid XML - ") + tinyxml2::XMLDocument::ErrorIDToName(error));
return false;
}
const tinyxml2::XMLElement * const rootnode = doc.FirstChildElement();
if (rootnode == nullptr) {
printError("Borland project file has no XML root node");
errors.emplace_back("Borland project file has no XML root node");
return false;
}

Expand Down Expand Up @@ -1296,12 +1296,12 @@ bool ImportProject::importCppcheckGuiProject(std::istream &istr, Settings &setti
const std::string xmldata = istream_to_string(istr);
const tinyxml2::XMLError error = doc.Parse(xmldata.data(), xmldata.size());
if (error != tinyxml2::XML_SUCCESS) {
printError(std::string("Cppcheck GUI project file is not a valid XML - ") + tinyxml2::XMLDocument::ErrorIDToName(error));
errors.emplace_back(std::string("Cppcheck GUI project file is not a valid XML - ") + tinyxml2::XMLDocument::ErrorIDToName(error));
return false;
}
const tinyxml2::XMLElement * const rootnode = doc.FirstChildElement();
if (rootnode == nullptr || strcmp(rootnode->Name(), CppcheckXml::ProjectElementName) != 0) {
printError("Cppcheck GUI project file has no XML root node");
errors.emplace_back("Cppcheck GUI project file has no XML root node");
return false;
}

Expand Down Expand Up @@ -1420,7 +1420,7 @@ bool ImportProject::importCppcheckGuiProject(std::istream &istr, Settings &setti
else if (strcmp(childname, Settings::SafeChecks::XmlExternalVariables) == 0)
temp.safeChecks.externalVariables = true;
else {
printError("Unknown '" + std::string(Settings::SafeChecks::XmlRootName) + "' element '" + childname + "' in Cppcheck project file");
errors.emplace_back("Unknown '" + std::string(Settings::SafeChecks::XmlRootName) + "' element '" + childname + "' in Cppcheck project file");
return false;
}
}
Expand All @@ -1443,7 +1443,7 @@ bool ImportProject::importCppcheckGuiProject(std::istream &istr, Settings &setti
else if (strcmp(name, CppcheckXml::ProjectNameElementName) == 0)
; // no-op
else {
printError("Unknown element '" + std::string(name) + "' in Cppcheck project file");
errors.emplace_back("Unknown element '" + std::string(name) + "' in Cppcheck project file");
return false;
}
}
Expand Down Expand Up @@ -1548,7 +1548,3 @@ void ImportProject::setRelativePaths(const std::string &filename)
}
}

void ImportProject::printError(const std::string &message)
{
std::cout << "cppcheck: error: " << message << std::endl;
}
5 changes: 2 additions & 3 deletions lib/importproject.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ class CPPCHECKLIB WARN_UNUSED ImportProject {
static void fsSetIncludePaths(FileSettings& fs, const std::string &basepath, const std::list<std::string> &in, std::map<std::string, std::string, cppcheck::stricmp> &variables);

std::list<FileSettings> fileSettings;
std::vector<std::string> errors;

ImportProject() = default;
virtual ~ImportProject() = default;
Expand Down Expand Up @@ -112,13 +113,11 @@ class CPPCHECKLIB WARN_UNUSED ImportProject {
};

bool importSln(std::istream &istr, const std::string &path, const std::vector<std::string> &fileFilters);
static SharedItemsProject importVcxitems(const std::string &filename, const std::vector<std::string> &fileFilters, std::vector<SharedItemsProject> &cache);
SharedItemsProject importVcxitems(const std::string &filename, const std::vector<std::string> &fileFilters, std::vector<SharedItemsProject> &cache);
bool importVcxproj(const std::string &filename, std::map<std::string, std::string, cppcheck::stricmp> &variables, const std::string &additionalIncludeDirectories, const std::vector<std::string> &fileFilters, std::vector<SharedItemsProject> &cache);
bool importVcxproj(const std::string &filename, const tinyxml2::XMLDocument &doc, std::map<std::string, std::string, cppcheck::stricmp> &variables, const std::string &additionalIncludeDirectories, const std::vector<std::string> &fileFilters, std::vector<SharedItemsProject> &cache);
bool importBcb6Prj(const std::string &projectFilename);

static void printError(const std::string &message);

void setRelativePaths(const std::string &filename);

std::string mPath;
Expand Down
9 changes: 6 additions & 3 deletions test/testimportproject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,8 @@ class TestImportProject : public TestFixture {
TestImporter importer;
ASSERT_EQUALS(false, importer.importCompileCommands(istr));
ASSERT_EQUALS(0, importer.fileSettings.size());
ASSERT_EQUALS("cppcheck: error: no 'arguments' or 'command' field found in compilation database entry\n", GET_REDIRECT_OUTPUT);
ASSERT_EQUALS(1, importer.errors.size());
ASSERT_EQUALS("no 'arguments' or 'command' field found in compilation database entry", importer.errors[0]);
}

void importCompileCommandsDirectoryMissing() const {
Expand All @@ -419,7 +420,8 @@ class TestImportProject : public TestFixture {
TestImporter importer;
ASSERT_EQUALS(false, importer.importCompileCommands(istr));
ASSERT_EQUALS(0, importer.fileSettings.size());
ASSERT_EQUALS("cppcheck: error: 'directory' field in compilation database entry missing\n", GET_REDIRECT_OUTPUT);
ASSERT_EQUALS(1, importer.errors.size());
ASSERT_EQUALS("'directory' field in compilation database entry missing", importer.errors[0]);
}

void importCompileCommandsDirectoryInvalid() const {
Expand All @@ -430,7 +432,8 @@ class TestImportProject : public TestFixture {
TestImporter importer;
ASSERT_EQUALS(false, importer.importCompileCommands(istr));
ASSERT_EQUALS(0, importer.fileSettings.size());
ASSERT_EQUALS("cppcheck: error: 'directory' field in compilation database entry is not a string\n", GET_REDIRECT_OUTPUT);
ASSERT_EQUALS(1, importer.errors.size());
ASSERT_EQUALS("'directory' field in compilation database entry is not a string", importer.errors[0]);
}

void importCppcheckGuiProject() const {
Expand Down