Skip to content

Commit

Permalink
fixed #13129 - apply --std with --clang / fixed usage of `Standar…
Browse files Browse the repository at this point in the history
…ds::stdValue`
  • Loading branch information
firewave committed Sep 25, 2024
1 parent 07883d5 commit cdbd63f
Show file tree
Hide file tree
Showing 8 changed files with 192 additions and 23 deletions.
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,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 @@ -935,6 +936,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;
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::uint64_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)

0 comments on commit cdbd63f

Please sign in to comment.