Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fixed #13129 - apply --std with --clang / fixed usage of Standards::stdValue #6742

Merged
merged 1 commit into from
Sep 29, 2024
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
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,7 @@ TESTOBJ = test/fixture.o \
test/testsimplifyusing.o \
test/testsingleexecutor.o \
test/testsizeof.o \
test/teststandards.o \
test/teststl.o \
test/teststring.o \
test/testsummaries.o \
Expand Down Expand Up @@ -943,6 +944,9 @@ test/testsingleexecutor.o: test/testsingleexecutor.cpp cli/executor.h cli/single
test/testsizeof.o: test/testsizeof.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/check.h lib/checksizeof.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/preprocessor.h lib/settings.h lib/standards.h lib/suppressions.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testsizeof.cpp

test/teststandards.o: test/teststandards.cpp lib/addoninfo.h lib/check.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/utils.h test/fixture.h
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/teststandards.cpp

test/teststl.o: test/teststl.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/check.h lib/checkstl.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/preprocessor.h lib/settings.h lib/standards.h lib/suppressions.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/teststl.cpp

Expand Down
7 changes: 1 addition & 6 deletions cli/cmdlineparser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1252,12 +1252,7 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a
// --std
else if (std::strncmp(argv[i], "--std=", 6) == 0) {
const std::string std = argv[i] + 6;
Standards tmp;
if (tmp.setC(std)) {
mSettings.standards.c = tmp.c;
} else if (tmp.setCPP(std)) {
mSettings.standards.cpp = tmp.cpp;
} else {
if (!mSettings.standards.setStd(std)) {
mLogger.printError("unknown --std value '" + std + "'");
return Result::Fail;
}
Expand Down
7 changes: 4 additions & 3 deletions lib/cppcheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -449,9 +449,10 @@ unsigned int CppCheck::checkClang(const FileWithDetails &file)
#endif

std::string flags(langOpt + " ");
// TODO: does not apply C standard
if (isCpp && !mSettings.standards.stdValue.empty())
flags += "-std=" + mSettings.standards.stdValue + " ";
if (isCpp && !mSettings.standards.stdValueCPP.empty())
flags += "-std=" + mSettings.standards.stdValueCPP + " ";
if (!isCpp && !mSettings.standards.stdValueC.empty())
flags += "-std=" + mSettings.standards.stdValueC + " ";

for (const std::string &i: mSettings.includePaths)
flags += "-I" + i + " ";
Expand Down
39 changes: 29 additions & 10 deletions lib/standards.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,27 @@ struct Standards {
enum cppstd_t : std::uint8_t { CPP03, CPP11, CPP14, CPP17, CPP20, CPP23, CPP26, CPPLatest = CPP26 } cpp = CPPLatest;

/** --std value given on command line */
std::string stdValue;
std::string stdValueC;

/** --std value given on command line */
std::string stdValueCPP;

bool setC(std::string str) {
stdValue = str;
Copy link
Owner

Choose a reason for hiding this comment

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

I just wonder if setC and setCPP are needed.

If only setStd is called from outside we could implement all the logic in that directly or make setC and setCPP private? I feel maybe the code would be a bit simpler but on the other hand testability is important too.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

That should be detected by the CI then. Maybe there is a conflict. Will take a look later. And more changes are coming and will integrate that cleanup if possible.

strTolower(str);
c = getC(str);
return !stdValue.empty() && str == getC();
if (str.empty())
return false;
const cstd_t c_new = getC(str);
const bool b = (str == getC(c_new));
if (b) {
c = c_new;
stdValueC = std::move(str);
}
return b;
}
std::string getC() const {
switch (c) {
return getC(c);
}
static std::string getC(cstd_t c_std) {
switch (c_std) {
case C89:
return "c89";
case C99:
Expand Down Expand Up @@ -86,10 +97,15 @@ struct Standards {
return Standards::CLatest;
}
bool setCPP(std::string str) {
stdValue = str;
strTolower(str);
cpp = getCPP(str);
return !stdValue.empty() && str == getCPP();
if (str.empty())
return false;
const cppstd_t cpp_new = getCPP(str);
const bool b = (str == getCPP(cpp_new));
if (b) {
cpp = cpp_new;
stdValueCPP = std::move(str);
}
return b;
}
std::string getCPP() const {
return getCPP(cpp);
Expand Down Expand Up @@ -137,6 +153,9 @@ struct Standards {
}
return Standards::CPPLatest;
}
bool setStd(const std::string& str) {
return setC(str) || setCPP(str);
}
};

/// @}
Expand Down
4 changes: 0 additions & 4 deletions test/cli/clang-import_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,22 +192,18 @@ def test_cmd_enforce_cpp(tmp_path): # #13128
__test_cmd(tmp_path, 'test.c',['-x', 'c++'], '-x c++')


@pytest.mark.xfail(strict=True)
def test_cmd_std_c(tmp_path): # #13129
__test_cmd(tmp_path, 'test.cpp',['--std=c89', '--std=c++14'], '-x c++ -std=c++14')


@pytest.mark.xfail(strict=True)
def test_cmd_std_cpp(tmp_path): # #13129
__test_cmd(tmp_path, 'test.c',['--std=c89', '--std=c++14'], '-x c -std=c89')


@pytest.mark.xfail(strict=True)
def test_cmd_std_c_enforce(tmp_path): # #13128/#13129
__test_cmd(tmp_path, 'test.cpp',['--language=c', '--std=c89', '--std=c++14'], '-x c -std=c89')


@pytest.mark.xfail(strict=True)
def test_cmd_std_cpp_enforce(tmp_path): # #13128/#13129
__test_cmd(tmp_path, 'test.c',['--language=c++', '--std=c89', '--std=c++14'], '-x c++ -std=c++14')

Expand Down
9 changes: 9 additions & 0 deletions test/fixture.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,14 @@ class TestFixture : public ErrorLogger {
assertEquals(filename, linenr, static_cast<std::int64_t>(expected), static_cast<std::int64_t>(actual), msg);
}

template<typename T>
void todoAssertEqualsEnum(const char* const filename, const unsigned int linenr, const T& wanted, const T& current, const T& actual) const {
if (std::is_unsigned<T>())
todoAssertEquals(filename, linenr, static_cast<std::uint64_t>(wanted), static_cast<std::uint64_t>(current), static_cast<std::uint64_t>(actual));
else
todoAssertEquals(filename, linenr, static_cast<std::int64_t>(wanted), static_cast<std::int64_t>(current), static_cast<std::int64_t>(actual));
}

void assertEquals(const char * filename, unsigned int linenr, const std::string &expected, const std::string &actual, const std::string &msg = emptyString) const;
void assertEqualsWithoutLineNumbers(const char * filename, unsigned int linenr, const std::string &expected, const std::string &actual, const std::string &msg = emptyString) const;
void assertEquals(const char * filename, unsigned int linenr, const char expected[], const std::string& actual, const std::string &msg = emptyString) const;
Expand Down Expand Up @@ -308,6 +316,7 @@ class TestInstance {
#define ASSERT_EQUALS_LOC_MSG( EXPECTED, ACTUAL, MSG, FILE_, LINE_ ) assertEquals(FILE_, LINE_, EXPECTED, ACTUAL, MSG)
#define ASSERT_EQUALS_MSG( EXPECTED, ACTUAL, MSG ) assertEquals(__FILE__, __LINE__, EXPECTED, ACTUAL, MSG)
#define ASSERT_EQUALS_ENUM( EXPECTED, ACTUAL ) assertEqualsEnum(__FILE__, __LINE__, (EXPECTED), (ACTUAL))
#define TODO_ASSERT_EQUALS_ENUM( WANTED, CURRENT, ACTUAL ) todoAssertEqualsEnum(__FILE__, __LINE__, WANTED, CURRENT, ACTUAL)
#define ASSERT_THROW( CMD, EXCEPTION ) do { try { (void)(CMD); assertThrowFail(__FILE__, __LINE__); } catch (const EXCEPTION&) {} catch (...) { assertThrowFail(__FILE__, __LINE__); } } while (false)
#define ASSERT_THROW_EQUALS( CMD, EXCEPTION, EXPECTED ) do { try { (void)(CMD); assertThrowFail(__FILE__, __LINE__); } catch (const EXCEPTION&e) { assertEquals(__FILE__, __LINE__, EXPECTED, e.errorMessage); } catch (...) { assertThrowFail(__FILE__, __LINE__); } } while (false)
#define ASSERT_THROW_EQUALS_2( CMD, EXCEPTION, EXPECTED ) do { try { (void)(CMD); assertThrowFail(__FILE__, __LINE__); } catch (const EXCEPTION&e) { assertEquals(__FILE__, __LINE__, EXPECTED, e.what()); } catch (...) { assertThrowFail(__FILE__, __LINE__); } } while (false)
Expand Down
1 change: 1 addition & 0 deletions test/testrunner.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
<ClCompile Include="testsimplifyusing.cpp" />
<ClCompile Include="testsingleexecutor.cpp" />
<ClCompile Include="testsizeof.cpp" />
<ClCompile Include="teststandards.cpp" />
<ClCompile Include="teststl.cpp" />
<ClCompile Include="teststring.cpp" />
<ClCompile Include="testsummaries.cpp" />
Expand Down
144 changes: 144 additions & 0 deletions test/teststandards.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
/*
* Cppcheck - A tool for static C/C++ code analysis
* Copyright (C) 2007-2024 Cppcheck team.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include "fixture.h"
#include "standards.h"

class TestStandards : public TestFixture {
public:
TestStandards() : TestFixture("TestStandards") {}

private:
void run() override {
TEST_CASE(set);
TEST_CASE(setAlias1);
TEST_CASE(setAlias2);
TEST_CASE(getC);
TEST_CASE(getCPP);
TEST_CASE(setStd);
}

void set() const {
Standards stds;
ASSERT_EQUALS_ENUM(Standards::CLatest, stds.c);
ASSERT_EQUALS("", stds.stdValueC);
ASSERT_EQUALS_ENUM(Standards::CPPLatest, stds.cpp);
ASSERT_EQUALS("", stds.stdValueCPP);

ASSERT_EQUALS(true, stds.setC("c99"));
ASSERT_EQUALS_ENUM(Standards::C99, stds.c);
ASSERT_EQUALS("c99", stds.stdValueC);
ASSERT_EQUALS_ENUM(Standards::CPPLatest, stds.cpp);
ASSERT_EQUALS("", stds.stdValueCPP);

ASSERT_EQUALS(true, stds.setC("c11"));
ASSERT_EQUALS_ENUM(Standards::C11, stds.c);
ASSERT_EQUALS("c11", stds.stdValueC);
ASSERT_EQUALS_ENUM(Standards::CPPLatest, stds.cpp);
ASSERT_EQUALS("", stds.stdValueCPP);

ASSERT_EQUALS(true, stds.setCPP("c++11"));
ASSERT_EQUALS_ENUM(Standards::C11, stds.c);
ASSERT_EQUALS("c11", stds.stdValueC);
ASSERT_EQUALS_ENUM(Standards::CPP11, stds.cpp);
ASSERT_EQUALS("c++11", stds.stdValueCPP);

ASSERT_EQUALS(true, stds.setCPP("c++23"));
ASSERT_EQUALS_ENUM(Standards::C11, stds.c);
ASSERT_EQUALS("c11", stds.stdValueC);
ASSERT_EQUALS_ENUM(Standards::CPP23, stds.cpp);
ASSERT_EQUALS("c++23", stds.stdValueCPP);

ASSERT_EQUALS(false, stds.setC("c77"));
ASSERT_EQUALS_ENUM(Standards::C11, stds.c);
ASSERT_EQUALS("c11", stds.stdValueC);
ASSERT_EQUALS_ENUM(Standards::CPP23, stds.cpp);
ASSERT_EQUALS("c++23", stds.stdValueCPP);

ASSERT_EQUALS(false, stds.setCPP("c+77"));
ASSERT_EQUALS_ENUM(Standards::C11, stds.c);
ASSERT_EQUALS("c11", stds.stdValueC);
ASSERT_EQUALS_ENUM(Standards::CPP23, stds.cpp);
ASSERT_EQUALS("c++23", stds.stdValueCPP);

ASSERT_EQUALS(false, stds.setC("C23"));
ASSERT_EQUALS_ENUM(Standards::C11, stds.c);
ASSERT_EQUALS("c11", stds.stdValueC);
ASSERT_EQUALS_ENUM(Standards::CPP23, stds.cpp);
ASSERT_EQUALS("c++23", stds.stdValueCPP);

ASSERT_EQUALS(false, stds.setCPP("C++11"));
ASSERT_EQUALS_ENUM(Standards::C11, stds.c);
ASSERT_EQUALS("c11", stds.stdValueC);
ASSERT_EQUALS_ENUM(Standards::CPP23, stds.cpp);
ASSERT_EQUALS("c++23", stds.stdValueCPP);
}

void setAlias1() const {
Standards stds;
TODO_ASSERT_EQUALS(true, false, stds.setCPP("gnu++11"));
ASSERT_EQUALS_ENUM(Standards::CLatest, stds.c);
ASSERT_EQUALS("", stds.stdValueC);
TODO_ASSERT_EQUALS_ENUM(Standards::CPP11, Standards::CPPLatest, stds.cpp);
TODO_ASSERT_EQUALS("gnu++11", "", stds.stdValueCPP);
}

void setAlias2() const {
Standards stds;
TODO_ASSERT_EQUALS(true, false, stds.setC("gnu17"));
TODO_ASSERT_EQUALS_ENUM(Standards::C17, Standards::CLatest, stds.c);
TODO_ASSERT_EQUALS("gnu17", "", stds.stdValueC);
ASSERT_EQUALS_ENUM(Standards::CPPLatest, stds.cpp);
ASSERT_EQUALS("", stds.stdValueCPP);
}

void getC() const {
ASSERT_EQUALS_ENUM(Standards::C99, Standards::getC("c99"));
ASSERT_EQUALS_ENUM(Standards::C11, Standards::getC("c11"));
TODO_ASSERT_EQUALS_ENUM(Standards::C17, Standards::CLatest, Standards::getC("gnu17"));
TODO_ASSERT_EQUALS_ENUM(Standards::C11, Standards::CLatest, Standards::getC("iso9899:2011"));

ASSERT_EQUALS_ENUM(Standards::CLatest, Standards::getC(""));
ASSERT_EQUALS_ENUM(Standards::CLatest, Standards::getC("c77"));
ASSERT_EQUALS_ENUM(Standards::CLatest, Standards::getC("C99"));
}

void getCPP() const {
ASSERT_EQUALS_ENUM(Standards::CPP11, Standards::getCPP("c++11"));
ASSERT_EQUALS_ENUM(Standards::CPP23, Standards::getCPP("c++23"));
TODO_ASSERT_EQUALS_ENUM(Standards::CPP23, Standards::CPPLatest, Standards::getCPP("gnu++23"));

ASSERT_EQUALS_ENUM(Standards::CPPLatest, Standards::getCPP(""));
ASSERT_EQUALS_ENUM(Standards::CPPLatest, Standards::getCPP("c++77"));
ASSERT_EQUALS_ENUM(Standards::CPPLatest, Standards::getCPP("C++11"));
}

void setStd() const {
Standards stds;
ASSERT(stds.setStd("c11"));
ASSERT(stds.setStd("c++11"));
TODO_ASSERT(stds.setStd("gnu11"));
TODO_ASSERT(stds.setStd("gnu++17"));
TODO_ASSERT(stds.setStd("iso9899:2011"));

ASSERT(!stds.setStd("C++11"));
ASSERT(!stds.setStd("Gnu++11"));
}
};

REGISTER_TEST(TestStandards)
Loading