Skip to content
Merged
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
40 changes: 25 additions & 15 deletions cli/cmdlineparser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -441,7 +441,9 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a
bool def = false;
bool maxconfigs = false;

ImportProject::Type projectType = ImportProject::Type::NONE;
ImportProject project;
std::string vsConfig;

bool executorAuto = true;

Expand Down Expand Up @@ -1160,17 +1162,16 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a

// --project
else if (std::strncmp(argv[i], "--project=", 10) == 0) {
if (project.projectType != ImportProject::Type::NONE)
if (projectType != ImportProject::Type::NONE)
{
mLogger.printError("multiple --project options are not supported.");
return Result::Fail;
}

mSettings.checkAllConfigurations = false; // Can be overridden with --max-configs or --force
std::string projectFile = argv[i]+10;
ImportProject::Type projType = project.import(projectFile, &mSettings, &mSuppressions);
project.projectType = projType;
if (projType == ImportProject::Type::CPPCHECK_GUI) {
projectType = project.import(projectFile, &mSettings, &mSuppressions);
if (projectType == ImportProject::Type::CPPCHECK_GUI) {
for (const std::string &lib : project.guiProject.libraries)
mSettings.libraries.emplace_back(lib);

Expand All @@ -1193,38 +1194,43 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a
if (!projectFileGui.empty()) {
// read underlying project
projectFile = projectFileGui;
projType = project.import(projectFileGui, &mSettings, &mSuppressions);
if (projType == ImportProject::Type::CPPCHECK_GUI) {
projectType = project.import(projectFileGui, &mSettings, &mSuppressions);
if (projectType == ImportProject::Type::CPPCHECK_GUI) {
mLogger.printError("nested Cppcheck GUI projects are not supported.");
return Result::Fail;
}
}
}
if (projType == ImportProject::Type::VS_SLN || projType == ImportProject::Type::VS_VCXPROJ) {
if (projectType == ImportProject::Type::VS_SLN || projectType == ImportProject::Type::VS_VCXPROJ) {
if (project.guiProject.analyzeAllVsConfigs == "false")
project.selectOneVsConfig(mSettings.platform.type);
mSettings.libraries.emplace_back("windows");
}
if (projType == ImportProject::Type::MISSING) {
if (projectType == ImportProject::Type::MISSING) {
mLogger.printError("failed to open project '" + projectFile + "'. The file does not exist.");
return Result::Fail;
}
if (projType == ImportProject::Type::UNKNOWN) {
if (projectType == ImportProject::Type::UNKNOWN) {
mLogger.printError("failed to load project '" + projectFile + "'. The format is unknown.");
return Result::Fail;
}
if (projType == ImportProject::Type::FAILURE) {
if (projectType == ImportProject::Type::FAILURE) {
mLogger.printError("failed to load project '" + projectFile + "'. An error occurred.");
return Result::Fail;
}
}

// --project-configuration
else if (std::strncmp(argv[i], "--project-configuration=", 24) == 0) {
mVSConfig = argv[i] + 24;
// TODO: provide error when this does nothing
if (!mVSConfig.empty() && (project.projectType == ImportProject::Type::VS_SLN || project.projectType == ImportProject::Type::VS_VCXPROJ))
project.ignoreOtherConfigs(mVSConfig);
vsConfig = argv[i] + 24;
if (vsConfig.empty()) {
mLogger.printError("--project-configuration parameter is empty.");
return Result::Fail;
}
if (projectType != ImportProject::Type::VS_SLN && projectType != ImportProject::Type::VS_VCXPROJ) {
mLogger.printError("--project-configuration has no effect - no Visual Studio project provided.");
return Result::Fail;
}
}

// Only print something when there are errors
Expand Down Expand Up @@ -1594,11 +1600,15 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a
//mLogger.printMessage("whole program analysis requires --cppcheck-build-dir to be active with -j.");
}

if (!mPathNames.empty() && project.projectType != ImportProject::Type::NONE) {
if (!mPathNames.empty() && projectType != ImportProject::Type::NONE) {
mLogger.printError("--project cannot be used in conjunction with source files.");
return Result::Fail;
}

if (!vsConfig.empty()) {
project.ignoreOtherConfigs(vsConfig);
}

if (!mSettings.buildDir.empty() && !Path::isDirectory(mSettings.buildDir)) {
mLogger.printError("Directory '" + mSettings.buildDir + "' specified by --cppcheck-build-dir argument has to be existent.");
return Result::Fail;
Expand Down
1 change: 0 additions & 1 deletion cli/cmdlineparser.h
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,6 @@ class CmdLineParser {
std::vector<std::string> mIgnoredPaths;
Settings &mSettings;
Suppressions &mSuppressions;
std::string mVSConfig;
};

/// @}
Expand Down
1 change: 0 additions & 1 deletion lib/importproject.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ 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;
Type projectType{Type::NONE};

ImportProject() = default;
virtual ~ImportProject() = default;
Expand Down
34 changes: 30 additions & 4 deletions test/cli/helloworld_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import json
import xml.etree.ElementTree as ET

import pytest

from testutils import create_gui_project_file, cppcheck

__script_dir = os.path.dirname(os.path.abspath(__file__))
Expand Down Expand Up @@ -145,16 +147,27 @@ def test_basepath_absolute_path():
assert ret == 0, stdout
assert stderr == '[main.c:5]: (error) Division by zero.\n'

def test_vs_project_local_path():
def __test_vs_project_local_path(extra_args=None, exp_vs_cfg='Debug|Win32 Debug|x64 Release|Win32 Release|x64'):
args = [
'--template=cppcheck1',
'--project=helloworld.vcxproj'
]
if extra_args:
args += extra_args
ret, stdout, stderr = cppcheck(args, cwd=__proj_dir)
assert ret == 0, stdout
assert __getVsConfigs(stdout, 'main.c') == 'Debug|Win32 Debug|x64 Release|Win32 Release|x64'
assert __getVsConfigs(stdout, 'main.c') == exp_vs_cfg
assert stderr == '[main.c:5]: (error) Division by zero.\n'

def test_vs_project_local_path():
__test_vs_project_local_path()

def test_vs_project_local_path_select_one():
__test_vs_project_local_path(['--project-configuration=Release|Win32'], 'Release|Win32')

def test_vs_project_local_path_select_one_multiple():
__test_vs_project_local_path(['--project-configuration=Debug|Win32', '--project-configuration=Release|Win32'], 'Release|Win32')

def test_vs_project_relative_path():
args = [
'--template=cppcheck1',
Expand All @@ -177,17 +190,30 @@ def test_vs_project_absolute_path():
assert __getVsConfigs(stdout, filename) == 'Debug|Win32 Debug|x64 Release|Win32 Release|x64'
assert stderr == '[%s:5]: (error) Division by zero.\n' % filename

def test_cppcheck_project_local_path():
def __test_cppcheck_project_local_path(extra_args=None, exp_vs_cfg='Debug|x64'):
args = [
'--template=cppcheck1',
'--platform=win64',
'--project=helloworld.cppcheck'
]
if extra_args:
args += extra_args
ret, stdout, stderr = cppcheck(args, cwd=__proj_dir)
assert ret == 0, stdout
assert __getVsConfigs(stdout, 'main.c') == 'Debug|x64'
assert __getVsConfigs(stdout, 'main.c') == exp_vs_cfg
assert stderr == '[main.c:5]: (error) Division by zero.\n'

def test_cppcheck_project_local_path():
__test_cppcheck_project_local_path()

@pytest.mark.xfail # TODO: no source files found
def test_cppcheck_project_local_path_select_one():
__test_cppcheck_project_local_path(['--project-configuration=Release|Win32'], 'Release|Win32')

@pytest.mark.xfail # TODO: no source files found
def test_cppcheck_project_local_path_select_one_multiple():
__test_cppcheck_project_local_path(['--project-configuration=Debug|Win32', '--project-configuration=Release|Win32'], 'Release|Win32')
Comment on lines +209 to +215
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have not looked into why it does not find source files. I will file a separate ticket about that later.

Part of this PR is needed for some other changes I am currently working on.


def test_cppcheck_project_relative_path():
args = [
'--template=cppcheck1',
Expand Down
16 changes: 16 additions & 0 deletions test/testcmdlineparser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,8 @@ class TestCmdlineParser : public TestFixture {
TEST_CASE(noCheckUnusedTemplates);
TEST_CASE(clangTidy);
TEST_CASE(clangTidyCustom);
TEST_CASE(projectConfigurationNoProject);
TEST_CASE(projectConfigurationEmpty);

TEST_CASE(ignorepaths1);
TEST_CASE(ignorepaths2);
Expand Down Expand Up @@ -3066,6 +3068,20 @@ class TestCmdlineParser : public TestFixture {
ASSERT_EQUALS("clang-tidy-14", settings->clangTidyExecutable);
}

void projectConfigurationNoProject() {
REDIRECT;
const char * const argv[] = {"cppcheck", "--project-configuration=Debug|Win32", "file.cpp"};
ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv));
ASSERT_EQUALS("cppcheck: error: --project-configuration has no effect - no Visual Studio project provided.\n", logger->str());
}

void projectConfigurationEmpty() {
REDIRECT;
const char * const argv[] = {"cppcheck", "--project-configuration=", "file.cpp"};
ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv));
ASSERT_EQUALS("cppcheck: error: --project-configuration parameter is empty.\n", logger->str());
}

void ignorepaths1() {
REDIRECT;
const char * const argv[] = {"cppcheck", "-isrc", "file.cpp"};
Expand Down
Loading