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
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -805,7 +805,7 @@ test/testsimplifytokens.o: test/testsimplifytokens.cpp lib/check.h lib/color.h l
test/testsimplifytypedef.o: test/testsimplifytypedef.cpp externals/simplecpp/simplecpp.h lib/check.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testsimplifytypedef.cpp

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

test/testsingleexecutor.o: test/testsingleexecutor.cpp cli/executor.h cli/singleexecutor.h lib/analyzerinfo.h lib/check.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.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/vfvalue.h test/fixture.h test/helpers.h test/redirect.h
Expand Down
47 changes: 35 additions & 12 deletions lib/tokenize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2760,11 +2760,23 @@ static bool scopesMatch(const std::string &scope1, const std::string &scope2, co
return false;
}

static unsigned int tokDistance(const Token* tok1, const Token* tok2) {
unsigned int dist = 0;
const Token* tok = tok1;
while (tok != tok2) {
++dist;
tok = tok->next();
}
return dist;
};

bool Tokenizer::simplifyUsing()
{
if (!isCPP() || mSettings->standards.cpp < Standards::CPP11)
return false;

const unsigned int maxReplacementTokens = 1000; // limit the number of tokens we replace

bool substitute = false;
ScopeInfo3 scopeInfo;
ScopeInfo3 *currentScope = &scopeInfo;
Expand Down Expand Up @@ -3006,6 +3018,12 @@ bool Tokenizer::simplifyUsing()
} else if (!usingMatch(nameToken, scope, &tok1, scope1, currentScope1, nullptr))
continue;

const auto nReplace = tokDistance(start, usingEnd);
if (nReplace > maxReplacementTokens) {
simplifyUsingError(usingStart, usingEnd);
continue;
}

// remove the qualification
std::string fullScope = scope;
std::string removed;
Expand Down Expand Up @@ -3187,18 +3205,7 @@ bool Tokenizer::simplifyUsing()
}
} else {
skip = true;
if (mSettings->debugwarnings && mErrorLogger) {
std::string str;
for (Token *tok3 = usingStart; tok3 && tok3 != usingEnd; tok3 = tok3->next()) {
if (!str.empty())
str += ' ';
str += tok3->str();
}
str += " ;";
std::list<const Token *> callstack(1, usingStart);
mErrorLogger->reportErr(ErrorMessage(callstack, &list, Severity::debug, "simplifyUsing",
"Failed to parse \'" + str + "\'. The checking continues anyway.", Certainty::normal));
}
simplifyUsingError(usingStart, usingEnd);
}
tok1 = after;
}
Expand Down Expand Up @@ -3233,6 +3240,22 @@ bool Tokenizer::simplifyUsing()
return substitute;
}

void Tokenizer::simplifyUsingError(const Token* usingStart, const Token* usingEnd)
{
if (mSettings->debugwarnings && mErrorLogger) {
std::string str;
for (const Token *tok = usingStart; tok && tok != usingEnd; tok = tok->next()) {
if (!str.empty())
str += ' ';
str += tok->str();
}
str += " ;";
std::list<const Token *> callstack(1, usingStart);
mErrorLogger->reportErr(ErrorMessage(callstack, &list, Severity::debug, "simplifyUsing",
"Failed to parse \'" + str + "\'. The checking continues anyway.", Certainty::normal));
}
}

bool Tokenizer::createTokens(std::istream &code,
const std::string& FileName)
{
Expand Down
1 change: 1 addition & 0 deletions lib/tokenize.h
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,7 @@ class CPPCHECKLIB Tokenizer {
/**
*/
bool simplifyUsing();
void simplifyUsingError(const Token* usingStart, const Token* usingEnd);

/** Simplify useless C++ empty namespaces, like: 'namespace %name% { }'*/
void simplifyEmptyNamespaces();
Expand Down
28 changes: 27 additions & 1 deletion test/testsimplifyusing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
#include "token.h"
#include "tokenize.h"

#include <simplecpp.h>

#include <sstream> // IWYU pragma: keep
#include <string>

Expand Down Expand Up @@ -92,20 +94,33 @@ class TestSimplifyUsing : public TestFixture {
TEST_CASE(simplifyUsing10172);
TEST_CASE(simplifyUsing10173);
TEST_CASE(simplifyUsing10335);
TEST_CASE(simplifyUsing10720);

TEST_CASE(scopeInfo1);
TEST_CASE(scopeInfo2);
}

#define tok(...) tok_(__FILE__, __LINE__, __VA_ARGS__)
std::string tok_(const char* file, int line, const char code[], cppcheck::Platform::Type type = cppcheck::Platform::Type::Native, bool debugwarnings = true) {
std::string tok_(const char* file, int line, const char code[], cppcheck::Platform::Type type = cppcheck::Platform::Type::Native, bool debugwarnings = true, bool preprocess = false) {
errout.str("");

settings0.certainty.enable(Certainty::inconclusive);
settings0.debugwarnings = debugwarnings;
PLATFORM(settings0.platform, type);
Tokenizer tokenizer(&settings0, this);

if (preprocess) {
std::vector<std::string> files{ "test.cpp" };
std::istringstream istr(code);
const simplecpp::TokenList tokens1(istr, files, files[0]);

simplecpp::TokenList tokens2(files);
std::map<std::string, simplecpp::TokenList*> filedata;
simplecpp::preprocess(tokens2, tokens1, files, filedata, simplecpp::DUI());

tokenizer.createTokens(std::move(tokens2));
}

std::istringstream istr(code);
ASSERT_LOC(tokenizer.tokenize(istr, "test.cpp"), file, line);

Expand Down Expand Up @@ -1346,6 +1361,17 @@ class TestSimplifyUsing : public TestFixture {
ASSERT_EQUALS(exp, tok(code));
}

void simplifyUsing10720() {
const char code[] = "template <typename... Ts>\n"
"struct S {};\n"
"#define STAMP(thiz, prev) using thiz = S<prev, prev, prev, prev, prev, prev, prev, prev, prev, prev>;\n"
"STAMP(A, int);\n"
"STAMP(B, A);\n"
"STAMP(C, B);\n";
tok(code, cppcheck::Platform::Type::Native, /*debugwarnings*/ true, /*preprocess*/ true);
ASSERT_EQUALS(errout.str().compare(0, 64, "[test.cpp:6]: (debug) Failed to parse 'using C = S < S < S < int"), 0);
}

void scopeInfo1() {
const char code[] = "struct A {\n"
" enum class Mode { UNKNOWN, ENABLED, NONE, };\n"
Expand Down