Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
10 changes: 5 additions & 5 deletions cli/cmdlineparser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1184,7 +1184,7 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a
}
if (projectType == ImportProject::Type::COMPILE_DB)
mSettings.maxConfigsProject = 1;
if (projectType == ImportProject::Type::VS_SLN || projectType == ImportProject::Type::VS_VCXPROJ) {
if (projectType == ImportProject::Type::VS_SLN || projectType == ImportProject::Type::VS_SLNX || projectType == ImportProject::Type::VS_VCXPROJ) {
mSettings.libraries.emplace_back("windows");
}
for (const auto &error : project.errors)
Expand All @@ -1210,7 +1210,7 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a
mLogger.printError("--project-configuration parameter is empty.");
return Result::Fail;
}
if (projectType != ImportProject::Type::VS_SLN && projectType != ImportProject::Type::VS_VCXPROJ) {
if (projectType != ImportProject::Type::VS_SLN && projectType != ImportProject::Type::VS_SLNX && projectType != ImportProject::Type::VS_VCXPROJ) {
mLogger.printError("--project-configuration has no effect - no Visual Studio project provided.");
return Result::Fail;
}
Expand Down Expand Up @@ -1645,7 +1645,7 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a
mSettings.platform.defaultSign = defaultSign;

if (!mSettings.analyzeAllVsConfigs) {
if (projectType != ImportProject::Type::VS_SLN && projectType != ImportProject::Type::VS_VCXPROJ) {
if (projectType != ImportProject::Type::VS_SLN && projectType != ImportProject::Type::VS_SLNX && projectType != ImportProject::Type::VS_VCXPROJ) {
if (mAnalyzeAllVsConfigsSetOnCmdLine) {
mLogger.printError("--no-analyze-all-vs-configs has no effect - no Visual Studio project provided.");
return Result::Fail;
Expand Down Expand Up @@ -1931,13 +1931,13 @@ void CmdLineParser::printHelp(bool premium) const

oss <<
" --project=<file> Run Cppcheck on project. The <file> can be a Visual\n"
" Studio Solution (*.sln), Visual Studio Project\n"
" Studio Solution (*.sln) or (*.slnx), Visual Studio Project\n"
" (*.vcxproj), compile database (compile_commands.json),\n"
" or Borland C++ Builder 6 (*.bpr). The files to analyse,\n"
" include paths, defines, platform and undefines in\n"
" the specified file will be used.\n"
" --project-configuration=<config>\n"
" If used together with a Visual Studio Solution (*.sln)\n"
" If used together with a Visual Studio Solution (*.sln) or (*.slnx)\n"
" or Visual Studio Project (*.vcxproj) you can limit\n"
" the configuration cppcheck should check.\n"
" For example: '--project-configuration=Release|Win32'\n"
Expand Down
6 changes: 4 additions & 2 deletions gui/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -767,7 +767,7 @@ QStringList MainWindow::selectFilesToAnalyze(QFileDialog::FileMode mode)
QMap<QString,QString> filters;
filters[tr("C/C++ Source")] = FileList::getDefaultFilters().join(" ");
filters[tr("Compile database")] = compile_commands_json;
filters[tr("Visual Studio")] = "*.sln *.vcxproj";
filters[tr("Visual Studio")] = "*.sln *.slnx *.vcxproj";
filters[tr("Borland C++ Builder 6")] = "*.bpr";
QString lastFilter = mSettings->value(SETTINGS_LAST_ANALYZE_FILES_FILTER).toString();
selected = QFileDialog::getOpenFileNames(this,
Expand Down Expand Up @@ -810,13 +810,14 @@ void MainWindow::analyzeFiles()

const QString file0 = (!selected.empty() ? selected[0].toLower() : QString());
if (file0.endsWith(".sln")
|| file0.endsWith(".slnx")
|| file0.endsWith(".vcxproj")
|| file0.endsWith(compile_commands_json)
|| file0.endsWith(".bpr")) {
ImportProject p;
p.import(selected[0].toStdString());

if (file0.endsWith(".sln")) {
if (file0.endsWith(".sln") || file0.endsWith(".slnx")) {
QStringList configs;
for (auto it = p.fileSettings.cbegin(); it != p.fileSettings.cend(); ++it) {
const QString cfg(QString::fromStdString(it->cfg));
Expand Down Expand Up @@ -1969,6 +1970,7 @@ void MainWindow::analyzeProject(const ProjectFile *projectFile, const QStringLis
switch (result) {
case ImportProject::Type::COMPILE_DB:
case ImportProject::Type::VS_SLN:
case ImportProject::Type::VS_SLNX:
case ImportProject::Type::VS_VCXPROJ:
case ImportProject::Type::BORLAND:
case ImportProject::Type::CPPCHECK_GUI:
Expand Down
6 changes: 3 additions & 3 deletions gui/projectfiledialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ static std::string suppressionAsText(const SuppressionList::Suppression& s)

QStringList ProjectFileDialog::getProjectConfigs(const QString &fileName)
{
if (!fileName.endsWith(".sln") && !fileName.endsWith(".vcxproj"))
if (!fileName.endsWith(".sln") && !fileName.endsWith(".slnx") && !fileName.endsWith(".vcxproj"))
return QStringList();
QStringList ret;
ImportProject importer;
Expand Down Expand Up @@ -612,7 +612,7 @@ void ProjectFileDialog::updatePathsAndDefines()
{
const QString &fileName = mUI->mEditImportProject->text();
const bool importProject = !fileName.isEmpty();
const bool hasConfigs = fileName.endsWith(".sln") || fileName.endsWith(".vcxproj");
const bool hasConfigs = fileName.endsWith(".sln") || fileName.endsWith(".slnx") || fileName.endsWith(".vcxproj");
mUI->mBtnClearImportProject->setEnabled(importProject);
mUI->mListCheckPaths->setEnabled(!importProject);
mUI->mListIncludeDirs->setEnabled(!importProject);
Expand Down Expand Up @@ -642,7 +642,7 @@ void ProjectFileDialog::browseImportProject()
const QFileInfo inf(mProjectFile->getFilename());
const QDir &dir = inf.absoluteDir();
QMap<QString,QString> filters;
filters[tr("Visual Studio")] = "*.sln *.vcxproj";
filters[tr("Visual Studio")] = "*.sln *.slnx *.vcxproj";
filters[tr("Compile database")] = "compile_commands.json";
filters[tr("Borland C++ Builder 6")] = "*.bpr";
QString fileName = QFileDialog::getOpenFileName(this, tr("Import Project"),
Expand Down
54 changes: 54 additions & 0 deletions lib/importproject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,12 @@ ImportProject::Type ImportProject::import(const std::string &filename, Settings
setRelativePaths(filename);
return ImportProject::Type::VS_SLN;
}
}
else if (endsWith(filename, ".slnx")) {
if (importSlnx(filename, fileFilters)) {
setRelativePaths(filename);
return ImportProject::Type::VS_SLNX;
}
} else if (endsWith(filename, ".vcxproj")) {
std::map<std::string, std::string, cppcheck::stricmp> variables;
std::vector<SharedItemsProject> sharedItemsProjects;
Expand Down Expand Up @@ -488,6 +494,54 @@ bool ImportProject::importSln(std::istream &istr, const std::string &path, const
return true;
}

bool ImportProject::importSlnx(const std::string& filename, const std::vector<std::string>& fileFilters)
{
tinyxml2::XMLDocument doc;
const tinyxml2::XMLError error = doc.LoadFile(filename.c_str());
if (error != tinyxml2::XML_SUCCESS) {
errors.emplace_back(std::string("Visual Studio project file is not a valid XML - ") + tinyxml2::XMLDocument::ErrorIDToName(error));
return false;
}

const tinyxml2::XMLElement* const rootnode = doc.FirstChildElement();
if (rootnode == nullptr) {
errors.emplace_back("Visual Studio project file has no XML root node");
return false;
}

std::map<std::string, std::string, cppcheck::stricmp> variables;
variables["SolutionDir"] = Path::simplifyPath(Path::getPathFromFilename(filename));

bool found = false;
std::vector<SharedItemsProject> sharedItemsProjects;

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;
}
found = true;
}
}
}

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

return true;
}

namespace {
struct ProjectConfiguration {
explicit ProjectConfiguration(const tinyxml2::XMLElement *cfg) {
Expand Down
2 changes: 2 additions & 0 deletions lib/importproject.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ class CPPCHECKLIB WARN_UNUSED ImportProject {
FAILURE,
COMPILE_DB,
VS_SLN,
VS_SLNX,
VS_VCXPROJ,
BORLAND,
CPPCHECK_GUI
Expand Down Expand Up @@ -113,6 +114,7 @@ class CPPCHECKLIB WARN_UNUSED ImportProject {
};

bool importSln(std::istream &istr, const std::string &path, const std::vector<std::string> &fileFilters);
bool importSlnx(const std::string& filename, const std::vector<std::string>& fileFilters);
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);
Expand Down
6 changes: 5 additions & 1 deletion man/manual.md
Original file line number Diff line number Diff line change
Expand Up @@ -309,12 +309,16 @@ To ignore certain folders you can use `-i`. This will skip analysis of source fi

## Visual Studio

You can run Cppcheck on individual project files (\*.vcxproj) or on a whole solution (\*.sln)
You can run Cppcheck on individual project files (\*.vcxproj) or on a whole solution (\*.sln) or (\*.slnx)

Running Cppcheck on an entire Visual Studio solution:

cppcheck --project=foobar.sln

Running Cppcheck on an entire Visual Studio 2026 solution:

cppcheck --project=foobar.slnx

Running Cppcheck on a Visual Studio project:

cppcheck --project=foobar.vcxproj
Expand Down
6 changes: 6 additions & 0 deletions test/cli/helloworld2/helloworld2.cppcheck
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="1">
<root name="."/>
<importproject>helloworld2.slnx</importproject>
<analyze-all-vs-configs>false</analyze-all-vs-configs>
</project>
7 changes: 7 additions & 0 deletions test/cli/helloworld2/helloworld2.slnx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<Solution>
<Configurations>
<Platform Name="x64" />
<Platform Name="x86" />
</Configurations>
<Project Path="helloworld2.vcxproj" />
</Solution>
123 changes: 123 additions & 0 deletions test/cli/helloworld2/helloworld2.vcxproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{7319858B-261C-4F0D-B022-92BB896242DD}</ProjectGuid>
<RootNamespace>helloworld2</RootNamespace>
<WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="main.c" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
11 changes: 11 additions & 0 deletions test/cli/helloworld2/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#include <stdio.h>

int main(void) {
(void)printf("Hello world!\n");
int x = 3 / 0; (void)x; // ERROR
return 0;
}

#ifdef SOME_CONFIG
void foo();
#endif
Loading
Loading