From defdfc0c4b81dae6e7e4849128ec135f57d715db Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Tue, 30 Jun 2026 18:33:01 -0400 Subject: [PATCH 1/5] add support for Folders and skip non C++ projects --- lib/importproject.cpp | 43 ++++++++++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/lib/importproject.cpp b/lib/importproject.cpp index 2d63fa8bbb7..09f6b892885 100644 --- a/lib/importproject.cpp +++ b/lib/importproject.cpp @@ -529,27 +529,48 @@ bool ImportProject::importSlnx(const std::string& filename, const std::vectorName(), "Solution") != 0) { + errors.emplace_back("Invalid Visual Studio solution file format"); + return false; + } + std::map variables; variables["SolutionDir"] = Path::simplifyPath(Path::getPathFromFilename(filename)); bool found = false; std::vector sharedItemsProjects; + auto processProject = [&](const tinyxml2::XMLElement* projectNode) { + const char* pathAttribute = projectNode->Attribute("Path"); + if (pathAttribute == nullptr) + return; + + std::string vcxproj(pathAttribute); + vcxproj = Path::toNativeSeparators(std::move(vcxproj)); + + if (Path::getFilenameExtensionInLowerCase(vcxproj) != ".vcxproj") + return; // skip other project types + + if (!Path::isAbsolute(vcxproj)) + vcxproj = variables["SolutionDir"] + vcxproj; + + vcxproj = Path::fromNativeSeparators(std::move(vcxproj)); + if (!importVcxproj(vcxproj, variables, "", fileFilters, sharedItemsProjects)) { + errors.emplace_back("failed to load '" + vcxproj + "' from Visual Studio solution"); + return; + } + found = true; + }; + for (const tinyxml2::XMLElement* node = rootnode->FirstChildElement(); node; node = node->NextSiblingElement()) { const char* name = node->Name(); if (std::strcmp(name, "Project") == 0) { - const char* labelAttribute = node->Attribute("Path"); - if (labelAttribute) { - std::string vcxproj(labelAttribute); - vcxproj = Path::toNativeSeparators(std::move(vcxproj)); - if (!Path::isAbsolute(vcxproj)) - vcxproj = variables["SolutionDir"] + vcxproj; - vcxproj = Path::fromNativeSeparators(std::move(vcxproj)); - if (!importVcxproj(vcxproj, variables, "", fileFilters, sharedItemsProjects)) { - errors.emplace_back("failed to load '" + vcxproj + "' from Visual Studio solution"); - return false; + processProject(node); + } else if (std::strcmp(name, "Folder") == 0) { + for (const tinyxml2::XMLElement* childNode = node->FirstChildElement(); childNode; childNode = childNode->NextSiblingElement()) { + if (std::strcmp(childNode->Name(), "Project") == 0) { + processProject(childNode); } - found = true; } } } From ff2b767ff6ab0cdb69bde3a651db8d91436497c6 Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Tue, 30 Jun 2026 23:55:26 -0400 Subject: [PATCH 2/5] fix ci --- .github/workflows/selfcheck.yml | 2 +- lib/importproject.cpp | 13 ++++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/.github/workflows/selfcheck.yml b/.github/workflows/selfcheck.yml index 6d100c4ddc8..1d9f963ddde 100644 --- a/.github/workflows/selfcheck.yml +++ b/.github/workflows/selfcheck.yml @@ -121,7 +121,7 @@ jobs: - name: Self check (unusedFunction / no test / no gui) run: | - supprs="--suppress=unusedFunction:lib/errorlogger.h:197 --suppress=unusedFunction:lib/importproject.cpp:1671 --suppress=unusedFunction:lib/importproject.cpp:1695" + supprs="--suppress=unusedFunction:lib/errorlogger.h:197 --suppress=unusedFunction:lib/importproject.cpp:1695 --suppress=unusedFunction:lib/importproject.cpp:1719" ./cppcheck -q --template=selfcheck --error-exitcode=1 --library=cppcheck-lib -D__CPPCHECK__ -D__GNUC__ --enable=unusedFunction,information --exception-handling -rp=. --project=cmake.output.notest_nogui/compile_commands.json --suppressions-list=.selfcheck_unused_suppressions --inline-suppr $supprs env: DISABLE_VALUEFLOW: 1 diff --git a/lib/importproject.cpp b/lib/importproject.cpp index 09f6b892885..0e6ca353480 100644 --- a/lib/importproject.cpp +++ b/lib/importproject.cpp @@ -543,13 +543,13 @@ bool ImportProject::importSlnx(const std::string& filename, const std::vectorAttribute("Path"); if (pathAttribute == nullptr) - return; + return true; std::string vcxproj(pathAttribute); vcxproj = Path::toNativeSeparators(std::move(vcxproj)); if (Path::getFilenameExtensionInLowerCase(vcxproj) != ".vcxproj") - return; // skip other project types + return true; // skip other project types if (!Path::isAbsolute(vcxproj)) vcxproj = variables["SolutionDir"] + vcxproj; @@ -557,19 +557,22 @@ bool ImportProject::importSlnx(const std::string& filename, const std::vectorFirstChildElement(); node; node = node->NextSiblingElement()) { const char* name = node->Name(); if (std::strcmp(name, "Project") == 0) { - processProject(node); + if (!processProject(node)) + return false; } else if (std::strcmp(name, "Folder") == 0) { for (const tinyxml2::XMLElement* childNode = node->FirstChildElement(); childNode; childNode = childNode->NextSiblingElement()) { if (std::strcmp(childNode->Name(), "Project") == 0) { - processProject(childNode); + if (!processProject(childNode)) + return false; } } } From 5d12bdaa032ba9681861ddcff8a730c6208610ce Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Wed, 1 Jul 2026 09:22:34 -0400 Subject: [PATCH 3/5] add test for missing project file in folder --- test/cli/project_test.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/test/cli/project_test.py b/test/cli/project_test.py index 7421ca406a6..ca288fb97fb 100644 --- a/test/cli/project_test.py +++ b/test/cli/project_test.py @@ -179,6 +179,26 @@ def test_slnx_project_file_not_found(tmpdir): __test_project_error(tmpdir, "slnx", content, expected) +def test_slnx_project_file_in_folder_not_found(tmpdir): + content = '\r\n' \ + "\r\n" \ + " \r\n" \ + ' \r\n' \ + ' \r\n' \ + " \r\n" \ + ' \r\n' \ + ' \r\n' \ + ' \r\n' \ + "\r\n" + + expected = "Visual Studio project file is not a valid XML - XML_ERROR_FILE_NOT_FOUND\n" \ + "cppcheck: error: failed to load '{}' from Visual Studio solution".format(os.path.join(tmpdir, "common/test.vcxproj")) + if sys.platform == "win32": + expected = expected.replace('\\', '/') + + __test_project_error(tmpdir, "slnx", content, expected) + + def test_vcxproj_no_xml_root(tmpdir): content = '' From 2517e6f2dd920e1a3a98e57c5336dc549fbf8192 Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Wed, 1 Jul 2026 13:28:04 -0400 Subject: [PATCH 4/5] add test for no project in folder --- test/cli/project_test.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/cli/project_test.py b/test/cli/project_test.py index ca288fb97fb..bc2ca761653 100644 --- a/test/cli/project_test.py +++ b/test/cli/project_test.py @@ -161,6 +161,22 @@ def test_slnx_no_projects(tmpdir): __test_project_error(tmpdir, "slnx", content, expected) +def test_slnx_no_projects_in_folder(tmpdir): + content = '\r\n' \ + "\r\n" \ + " \r\n" \ + ' \r\n' \ + ' \r\n' \ + " \r\n" \ + ' \r\n' \ + ' \r\n' \ + "\r\n" + + expected = "no projects found in Visual Studio solution file" + + __test_project_error(tmpdir, "slnx", content, expected) + + def test_slnx_project_file_not_found(tmpdir): content = '\r\n' \ "\r\n" \ From 1d324a26ab956609781123a2a961d6ffbf07c904 Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Wed, 1 Jul 2026 13:34:12 -0400 Subject: [PATCH 5/5] add test for invalid xml root --- test/cli/project_test.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/cli/project_test.py b/test/cli/project_test.py index bc2ca761653..64bb406a709 100644 --- a/test/cli/project_test.py +++ b/test/cli/project_test.py @@ -147,6 +147,16 @@ def test_slnx_no_xml_root(tmpdir): __test_project_error(tmpdir, "slnx", content, expected) +def test_slnx_invalid_xml_root(tmpdir): + content = '\r\n' \ + "\r\n" \ + "\r\n" + + expected = "Invalid Visual Studio solution file format" + + __test_project_error(tmpdir, "slnx", content, expected) + + def test_slnx_no_projects(tmpdir): content = '\r\n' \ "\r\n" \