added (partial) support for specifying C++23 and support more "-std" options (#3212)

This commit is contained in:
Oliver Stöneberg 2022-04-15 16:17:36 +02:00 committed by GitHub
parent 6e69b751eb
commit 8f728cb4b6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 5412 additions and 2319 deletions

View File

@ -495,7 +495,7 @@ $(libcppdir)/errortypes.o: lib/errortypes.cpp lib/config.h lib/errortypes.h
$(libcppdir)/forwardanalyzer.o: lib/forwardanalyzer.cpp lib/analyzer.h lib/astutils.h lib/config.h lib/errortypes.h lib/forwardanalyzer.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/utils.h lib/valueflow.h lib/valueptr.h
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o $(libcppdir)/forwardanalyzer.o $(libcppdir)/forwardanalyzer.cpp
$(libcppdir)/importproject.o: lib/importproject.cpp externals/picojson/picojson.h externals/tinyxml2/tinyxml2.h lib/config.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h
$(libcppdir)/importproject.o: lib/importproject.cpp externals/picojson/picojson.h externals/simplecpp/simplecpp.h externals/tinyxml2/tinyxml2.h lib/config.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o $(libcppdir)/importproject.o $(libcppdir)/importproject.cpp
$(libcppdir)/infer.o: lib/infer.cpp lib/calculate.h lib/config.h lib/errortypes.h lib/infer.h lib/mathlib.h lib/valueflow.h lib/valueptr.h

View File

@ -768,22 +768,19 @@ bool CmdLineParser::parseFromArgs(int argc, const char* const argv[])
}
// --std
else if (std::strcmp(argv[i], "--std=c89") == 0) {
mSettings->standards.c = Standards::C89;
} else if (std::strcmp(argv[i], "--std=c99") == 0) {
mSettings->standards.c = Standards::C99;
} else if (std::strcmp(argv[i], "--std=c11") == 0) {
mSettings->standards.c = Standards::C11;
} else if (std::strcmp(argv[i], "--std=c++03") == 0) {
mSettings->standards.cpp = Standards::CPP03;
} else if (std::strcmp(argv[i], "--std=c++11") == 0) {
mSettings->standards.cpp = Standards::CPP11;
} else if (std::strcmp(argv[i], "--std=c++14") == 0) {
mSettings->standards.cpp = Standards::CPP14;
} else if (std::strcmp(argv[i], "--std=c++17") == 0) {
mSettings->standards.cpp = Standards::CPP17;
} else if (std::strcmp(argv[i], "--std=c++20") == 0) {
mSettings->standards.cpp = Standards::CPP20;
else if (std::strncmp(argv[i], "--std=", 6) == 0) {
const std::string std = argv[i] + 6;
// TODO: print error when standard is unknown
if (std::strncmp(std.c_str(), "c++", 3) == 0) {
mSettings->standards.cpp = Standards::getCPP(std);
}
else if (std::strncmp(std.c_str(), "c", 1) == 0) {
mSettings->standards.c = Standards::getC(std);
}
else {
printError("unknown --std value '" + std + "'");
return false;
}
}
else if (std::strncmp(argv[i], "--suppress=", 11) == 0) {

View File

@ -201,22 +201,10 @@ void CheckThread::runAddonsAndTools(const ImportProject::FileSettings *fileSetti
if (!fileSettings->standard.empty())
args << ("-std=" + QString::fromStdString(fileSettings->standard));
else {
switch (mCppcheck.settings().standards.cpp) {
case Standards::CPP03:
args << "-std=c++03";
break;
case Standards::CPP11:
args << "-std=c++11";
break;
case Standards::CPP14:
args << "-std=c++14";
break;
case Standards::CPP17:
args << "-std=c++17";
break;
case Standards::CPP20:
args << "-std=c++20";
break;
// TODO: pass C or C++ standard based on file type
const std::string std = mCppcheck.settings().standards.getCPP();
if (!std.empty()) {
args << ("-std=" + QString::fromStdString(std));
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -229,6 +229,7 @@ MainWindow::MainWindow(TranslationHandler* th, QSettings* settings) :
mUI->mActionCpp14->setActionGroup(mCppStandardActions);
mUI->mActionCpp17->setActionGroup(mCppStandardActions);
mUI->mActionCpp20->setActionGroup(mCppStandardActions);
//mUI->mActionCpp23->setActionGroup(mCppStandardActions);
mUI->mActionEnforceC->setActionGroup(mSelectLanguageActions);
mUI->mActionEnforceCpp->setActionGroup(mSelectLanguageActions);
@ -315,6 +316,7 @@ void MainWindow::loadSettings()
mUI->mActionCpp14->setChecked(standards.cpp == Standards::CPP14);
mUI->mActionCpp17->setChecked(standards.cpp == Standards::CPP17);
mUI->mActionCpp20->setChecked(standards.cpp == Standards::CPP20);
//mUI->mActionCpp23->setChecked(standards.cpp == Standards::CPP23);
// Main window settings
const bool showMainToolbar = mSettings->value(SETTINGS_TOOLBARS_MAIN_SHOW, true).toBool();
@ -397,6 +399,8 @@ void MainWindow::saveSettings() const
mSettings->setValue(SETTINGS_STD_CPP, "C++17");
if (mUI->mActionCpp20->isChecked())
mSettings->setValue(SETTINGS_STD_CPP, "C++20");
//if (mUI.mActionCpp23->isChecked())
// mSettings->setValue(SETTINGS_STD_CPP, "C++23");
// Main window settings
mSettings->setValue(SETTINGS_TOOLBARS_MAIN_SHOW, mUI->mToolBarMain->isVisible());

View File

@ -139,6 +139,7 @@
<addaction name="mActionCpp14"/>
<addaction name="mActionCpp17"/>
<addaction name="mActionCpp20"/>
<!--addaction name="mActionCpp23"/-->
</widget>
<widget class="QMenu" name="menuC_standard">
<property name="title">
@ -840,6 +841,17 @@
<string>C++20</string>
</property>
</action>
<!--action name="mActionCpp23">
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="text">
<string>C++23</string>
</property>
</action-->
</widget>
<customwidgets>
<customwidget>

View File

@ -3488,9 +3488,7 @@ void CheckOther::checkKnownArgument()
continue;
// ensure that function name does not contain "assert"
std::string funcname = tok->astParent()->previous()->str();
std::transform(funcname.begin(), funcname.end(), funcname.begin(), [](int c) {
return std::tolower(c);
});
strTolower(funcname);
if (funcname.find("assert") != std::string::npos)
continue;
knownArgumentError(tok, tok->astParent()->previous(), &tok->values().front(), varexpr, isVariableExprHidden);

View File

@ -37,6 +37,8 @@
#include <tinyxml2.h>
#include <simplecpp.h>
#define PICOJSON_USE_INT64
#include <picojson.h>
@ -314,18 +316,9 @@ void ImportProject::FileSettings::parseCommand(std::string command)
++pos;
const std::string stdval = readUntil(command, &pos, " ");
standard = stdval;
// TODO: use simplecpp::DUI::std instead of specifying it manually
if (standard.compare(0, 3, "c++") || standard.compare(0, 5, "gnu++")) {
std::string stddef;
if (standard == "c++98" || standard == "gnu++98" || standard == "c++03" || standard == "gnu++03") {
stddef = "199711L";
} else if (standard == "c++11" || standard == "gnu++11" || standard == "c++0x" || standard == "gnu++0x") {
stddef = "201103L";
} else if (standard == "c++14" || standard == "gnu++14" || standard == "c++1y" || standard == "gnu++1y") {
stddef = "201402L";
} else if (standard == "c++17" || standard == "gnu++17" || standard == "c++1z" || standard == "gnu++1z") {
stddef = "201703L";
}
const std::string stddef = simplecpp::getCppStdString(standard);
if (stddef.empty()) {
// TODO: log error
continue;
@ -335,21 +328,7 @@ void ImportProject::FileSettings::parseCommand(std::string command)
defs += stddef;
defs += ";";
} else if (standard.compare(0, 1, "c") || standard.compare(0, 3, "gnu")) {
if (standard == "c90" || standard == "iso9899:1990" || standard == "gnu90" || standard == "iso9899:199409") {
// __STDC_VERSION__ is not set for C90 although the macro was added in the 1994 amendments
continue;
}
std::string stddef;
if (standard == "c99" || standard == "iso9899:1999" || standard == "gnu99") {
stddef = "199901L";
} else if (standard == "c11" || standard == "iso9899:2011" || standard == "gnu11" || standard == "c1x" || standard == "gnu1x") {
stddef = "201112L";
} else if (standard == "c17") {
stddef = "201710L";
}
const std::string stddef = simplecpp::getCStdString(standard);
if (stddef.empty()) {
// TODO: log error
continue;
@ -808,14 +787,7 @@ bool ImportProject::importVcxproj(const std::string &filename, std::map<std::str
for (const ItemDefinitionGroup &i : itemDefinitionGroupList) {
if (!i.conditionIsTrue(p))
continue;
if (i.cppstd == Standards::CPP11)
fs.standard = "c++11";
else if (i.cppstd == Standards::CPP14)
fs.standard = "c++14";
else if (i.cppstd == Standards::CPP17)
fs.standard = "c++17";
else if (i.cppstd == Standards::CPP20)
fs.standard = "c++20";
fs.standard = Standards::getCPP(i.cppstd);
fs.defines += ';' + i.preprocessorDefinitions;
if (i.enhancedInstructionSet == "StreamingSIMDExtensions")
fs.defines += ";__SSE__";

View File

@ -90,13 +90,6 @@ bool Path::sameFileName(const std::string &fname1, const std::string &fname2)
return caseInsensitiveFilesystem() ? (caseInsensitiveStringCompare(fname1, fname2) == 0) : (fname1 == fname2);
}
// This wrapper exists because Sun's CC does not allow a static_cast
// from extern "C" int(*)(int) to int(*)(int).
static int tolowerWrapper(int c)
{
return std::tolower(c);
}
std::string Path::removeQuotationMarks(std::string path)
{
path.erase(std::remove(path.begin(), path.end(), '\"'), path.end());
@ -113,7 +106,7 @@ std::string Path::getFilenameExtension(const std::string &path)
if (caseInsensitiveFilesystem()) {
// on a case insensitive filesystem the case doesn't matter so
// let's return the extension in lowercase
std::transform(extension.begin(), extension.end(), extension.begin(), tolowerWrapper);
strTolower(extension);
}
return extension;
}
@ -121,7 +114,7 @@ std::string Path::getFilenameExtension(const std::string &path)
std::string Path::getFilenameExtensionInLowerCase(const std::string &path)
{
std::string extension = getFilenameExtension(path);
std::transform(extension.begin(), extension.end(), extension.begin(), tolowerWrapper);
strTolower(extension);
return extension;
}

View File

@ -30,7 +30,7 @@ PathMatch::PathMatch(const std::vector<std::string> &excludedPaths, bool caseSen
{
if (!mCaseSensitive)
for (std::string& excludedPath : mExcludedPaths)
std::transform(excludedPath.begin(), excludedPath.end(), excludedPath.begin(), ::tolower);
strTolower(excludedPath);
mWorkingDirectory.push_back(Path::getCurrentPath());
}
@ -44,7 +44,7 @@ bool PathMatch::match(const std::string &path) const
std::string findpath = Path::fromNativeSeparators(path);
if (!mCaseSensitive)
std::transform(findpath.begin(), findpath.end(), findpath.begin(), ::tolower);
strTolower(findpath);
// Filtering directory name
if (endsWith(excludedPath,'/')) {

View File

@ -621,8 +621,11 @@ static simplecpp::DUI createDUI(const Settings &mSettings, const std::string &cf
dui.undefined = mSettings.userUndefs; // -U
dui.includePaths = mSettings.includePaths; // -I
dui.includes = mSettings.userIncludes; // --include
// TODO: use mSettings.standards.stdValue instead
if (Path::isCPP(filename))
dui.std = mSettings.standards.getCPP();
else
dui.std = mSettings.standards.getC();
return dui;
}

View File

@ -21,6 +21,8 @@
#define standardsH
//---------------------------------------------------------------------------
#include "utils.h"
#include <string>
/// @addtogroup Core
@ -32,17 +34,17 @@
* This struct contains all possible standards that cppcheck recognize.
*/
struct Standards {
/** C code C89/C99/C11 standard */
/** C code standard */
enum cstd_t { C89, C99, C11, CLatest=C11 } c;
/** C++ code standard */
enum cppstd_t { CPP03, CPP11, CPP14, CPP17, CPP20, CPPLatest=CPP20 } cpp;
enum cppstd_t { CPP03, CPP11, CPP14, CPP17, CPP20, CPP23, CPPLatest=CPP23 } cpp;
/** --std value given on command line */
std::string stdValue;
/** This constructor clear all the variables **/
Standards() : c(C11), cpp(CPPLatest) {}
Standards() : c(CLatest), cpp(CPPLatest) {}
bool setC(const std::string& str) {
stdValue = str;
@ -71,32 +73,29 @@ struct Standards {
}
return "";
}
bool setCPP(const std::string& str) {
static cstd_t getC(const std::string &std) {
if (std == "c89") {
return Standards::C89;
}
if (std == "c99") {
return Standards::C99;
}
if (std == "c11") {
return Standards::C11;
}
return Standards::CLatest;
}
bool setCPP(std::string str) {
stdValue = str;
if (str == "c++03" || str == "C++03") {
cpp = CPP03;
return true;
}
if (str == "c++11" || str == "C++11") {
cpp = CPP11;
return true;
}
if (str == "c++14" || str == "C++14") {
cpp = CPP14;
return true;
}
if (str == "c++17" || str == "C++17") {
cpp = CPP17;
return true;
}
if (str == "c++20" || str == "C++20") {
cpp = CPP20;
return true;
}
return false;
strTolower(str);
cpp = getCPP(str);
return !stdValue.empty() && str == getCPP();
}
std::string getCPP() const {
switch (cpp) {
return getCPP(cpp);
}
static std::string getCPP(cppstd_t std) {
switch (std) {
case CPP03:
return "c++03";
case CPP11:
@ -107,9 +106,32 @@ struct Standards {
return "c++17";
case CPP20:
return "c++20";
case CPP23:
return "c++23";
}
return "";
}
static cppstd_t getCPP(const std::string &std) {
if (std == "c++03") {
return Standards::CPP03;
}
if (std == "c++11") {
return Standards::CPP11;
}
if (std == "c++14") {
return Standards::CPP14;
}
if (std == "c++17") {
return Standards::CPP17;
}
if (std == "c++20") {
return Standards::CPP20;
}
if (std == "c++23") {
return Standards::CPP23;
}
return Standards::CPPLatest;
}
};
/// @}

View File

@ -18,6 +18,7 @@
#include "utils.h"
#include <algorithm>
#include <cctype>
#include <iterator>
#include <memory>
@ -120,3 +121,13 @@ bool matchglobs(const std::vector<std::string> &patterns, const std::string &nam
return matchglob(pattern, name);
});
}
void strTolower(std::string& str)
{
// This wrapper exists because Sun's CC does not allow a static_cast
// from extern "C" int(*)(int) to int(*)(int).
static auto tolowerWrapper = [](int c) {
return std::tolower(c);
};
std::transform(str.begin(), str.end(), str.begin(), tolowerWrapper);
}

View File

@ -154,4 +154,6 @@ CPPCHECKLIB bool matchglob(const std::string& pattern, const std::string& name);
CPPCHECKLIB bool matchglobs(const std::vector<std::string> &patterns, const std::string &name);
CPPCHECKLIB void strTolower(std::string& str);
#endif

View File

@ -104,6 +104,7 @@ private:
TEST_CASE(reportProgressTest); // "Test" suffix to avoid hiding the parent's reportProgress
TEST_CASE(stdc99);
TEST_CASE(stdcpp11);
TEST_CASE(stdunknown);
TEST_CASE(platform);
TEST_CASE(plistEmpty);
TEST_CASE(plistDoesNotExist);
@ -711,6 +712,22 @@ private:
ASSERT(settings.standards.cpp == Standards::CPP11);
}
void stdunknown() {
REDIRECT;
{
CLEAR_REDIRECT_OUTPUT;
const char *const argv[] = {"cppcheck", "--std=d++11", "file.cpp"};
ASSERT(!defParser.parseFromArgs(3, argv));
ASSERT_EQUALS("cppcheck: error: unknown --std value 'd++11'\n", GET_REDIRECT_OUTPUT);
}
{
CLEAR_REDIRECT_OUTPUT;
const char *const argv[] = {"cppcheck", "--std=cplusplus11", "file.cpp"};
TODO_ASSERT(!defParser.parseFromArgs(3, argv));
TODO_ASSERT_EQUALS("cppcheck: error: unknown --std value 'cplusplus11'\n", "", GET_REDIRECT_OUTPUT);
}
}
void platform() {
REDIRECT;
const char * const argv[] = {"cppcheck", "--platform=win64", "file.cpp"};

View File

@ -209,6 +209,7 @@ private:
TEST_CASE(predefine3);
TEST_CASE(predefine4);
TEST_CASE(predefine5); // automatically define __cplusplus
TEST_CASE(predefine6); // automatically define __STDC_VERSION__
TEST_CASE(invalidElIf); // #2942 segfault
@ -1996,8 +1997,14 @@ private:
void predefine5() { // #3737, #5119 - automatically define __cplusplus
// #3737...
const char code[] = "#ifdef __cplusplus\n123\n#endif";
ASSERT_EQUALS("", preprocessor0.getcode(code, "X=123", "test.c"));
ASSERT_EQUALS("\n123", preprocessor0.getcode(code, "X=123", "test.cpp"));
ASSERT_EQUALS("", preprocessor0.getcode(code, "", "test.c"));
ASSERT_EQUALS("\n123", preprocessor0.getcode(code, "", "test.cpp"));
}
void predefine6() { // automatically define __STDC_VERSION__
const char code[] = "#ifdef __STDC_VERSION__\n123\n#endif";
ASSERT_EQUALS("\n123", preprocessor0.getcode(code, "", "test.c"));
ASSERT_EQUALS("", preprocessor0.getcode(code, "", "test.cpp"));
}
void invalidElIf() {