* Fixed #8960 ("(debug) Unknown type 'x'." with alias in template class alias) This commit adds non-template type alias support to the template simplifier. Only relatively simple type aliases are supported at this time. More complex types will be added later. --debug-warnings will show unsupported type aliases. Type alias support will be removed from the symbol database in the future. Type alias tests have been removed from the symbol database tests. * Add the changes. * Fix codacy warning. * Fix travis warnings.
This commit is contained in:
parent
a8cb6fd1a1
commit
1faae52d06
4
Makefile
4
Makefile
|
@ -225,6 +225,7 @@ TESTOBJ = test/options.o \
|
||||||
test/testsimplifytemplate.o \
|
test/testsimplifytemplate.o \
|
||||||
test/testsimplifytokens.o \
|
test/testsimplifytokens.o \
|
||||||
test/testsimplifytypedef.o \
|
test/testsimplifytypedef.o \
|
||||||
|
test/testsimplifyusing.o \
|
||||||
test/testsizeof.o \
|
test/testsizeof.o \
|
||||||
test/teststl.o \
|
test/teststl.o \
|
||||||
test/teststring.o \
|
test/teststring.o \
|
||||||
|
@ -625,6 +626,9 @@ test/testsimplifytokens.o: test/testsimplifytokens.cpp lib/platform.h lib/config
|
||||||
test/testsimplifytypedef.o: test/testsimplifytypedef.cpp lib/platform.h lib/config.h lib/settings.h lib/errorlogger.h lib/suppressions.h lib/importproject.h lib/utils.h lib/library.h lib/mathlib.h lib/standards.h lib/timer.h test/testsuite.h lib/token.h lib/valueflow.h lib/templatesimplifier.h lib/tokenize.h lib/tokenlist.h
|
test/testsimplifytypedef.o: test/testsimplifytypedef.cpp lib/platform.h lib/config.h lib/settings.h lib/errorlogger.h lib/suppressions.h lib/importproject.h lib/utils.h lib/library.h lib/mathlib.h lib/standards.h lib/timer.h test/testsuite.h lib/token.h lib/valueflow.h lib/templatesimplifier.h lib/tokenize.h lib/tokenlist.h
|
||||||
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o test/testsimplifytypedef.o test/testsimplifytypedef.cpp
|
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o test/testsimplifytypedef.o test/testsimplifytypedef.cpp
|
||||||
|
|
||||||
|
test/testsimplifyusing.o: test/testsimplifyusing.cpp lib/platform.h lib/config.h lib/settings.h lib/errorlogger.h lib/suppressions.h lib/importproject.h lib/utils.h lib/library.h lib/mathlib.h lib/standards.h lib/timer.h test/testsuite.h lib/token.h lib/valueflow.h lib/templatesimplifier.h lib/tokenize.h lib/tokenlist.h
|
||||||
|
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o test/testsimplifyusing.o test/testsimplifyusing.cpp
|
||||||
|
|
||||||
test/testsizeof.o: test/testsizeof.cpp lib/checksizeof.h lib/check.h lib/config.h lib/errorlogger.h lib/suppressions.h lib/settings.h lib/importproject.h lib/platform.h lib/utils.h lib/library.h lib/mathlib.h lib/standards.h lib/timer.h lib/token.h lib/valueflow.h lib/templatesimplifier.h lib/tokenize.h lib/tokenlist.h test/testsuite.h
|
test/testsizeof.o: test/testsizeof.cpp lib/checksizeof.h lib/check.h lib/config.h lib/errorlogger.h lib/suppressions.h lib/settings.h lib/importproject.h lib/platform.h lib/utils.h lib/library.h lib/mathlib.h lib/standards.h lib/timer.h lib/token.h lib/valueflow.h lib/templatesimplifier.h lib/tokenize.h lib/tokenlist.h test/testsuite.h
|
||||||
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o test/testsizeof.o test/testsizeof.cpp
|
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o test/testsizeof.o test/testsizeof.cpp
|
||||||
|
|
||||||
|
|
|
@ -146,7 +146,7 @@ TemplateSimplifier::TokenAndName::~TokenAndName()
|
||||||
}
|
}
|
||||||
|
|
||||||
TemplateSimplifier::TemplateSimplifier(Tokenizer *tokenizer)
|
TemplateSimplifier::TemplateSimplifier(Tokenizer *tokenizer)
|
||||||
: mTokenList(tokenizer->list), mSettings(tokenizer->mSettings), mErrorLogger(tokenizer->mErrorLogger)
|
: mTokenizer(tokenizer), mTokenList(tokenizer->list), mSettings(tokenizer->mSettings), mErrorLogger(tokenizer->mErrorLogger)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -520,12 +520,14 @@ namespace {
|
||||||
static std::string getScopeName(const std::list<ScopeInfo2> &scopeInfo)
|
static std::string getScopeName(const std::list<ScopeInfo2> &scopeInfo)
|
||||||
{
|
{
|
||||||
std::string ret;
|
std::string ret;
|
||||||
for (const ScopeInfo2 &i : scopeInfo)
|
for (const ScopeInfo2 &i : scopeInfo) {
|
||||||
|
if (!i.name.empty())
|
||||||
ret += (ret.empty() ? "" : " :: ") + i.name;
|
ret += (ret.empty() ? "" : " :: ") + i.name;
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setScopeInfo(Token *tok, std::list<ScopeInfo2> *scopeInfo)
|
static void setScopeInfo(Token *tok, std::list<ScopeInfo2> *scopeInfo, bool all = false)
|
||||||
{
|
{
|
||||||
while (tok->str() == "}" && !scopeInfo->empty() && tok == scopeInfo->back().bodyEnd)
|
while (tok->str() == "}" && !scopeInfo->empty() && tok == scopeInfo->back().bodyEnd)
|
||||||
scopeInfo->pop_back();
|
scopeInfo->pop_back();
|
||||||
|
@ -544,6 +546,7 @@ static void setScopeInfo(Token *tok, std::list<ScopeInfo2> *scopeInfo)
|
||||||
}
|
}
|
||||||
// check for member function
|
// check for member function
|
||||||
else if (tok->str() == "{") {
|
else if (tok->str() == "{") {
|
||||||
|
bool added = false;
|
||||||
Token *tok1 = tok;
|
Token *tok1 = tok;
|
||||||
while (Token::Match(tok1->previous(), "const|volatile|final|override|&|&&|noexcept"))
|
while (Token::Match(tok1->previous(), "const|volatile|final|override|&|&&|noexcept"))
|
||||||
tok1 = tok1->previous();
|
tok1 = tok1->previous();
|
||||||
|
@ -570,8 +573,12 @@ static void setScopeInfo(Token *tok, std::list<ScopeInfo2> *scopeInfo)
|
||||||
tok1 = tok1->tokAt(-2);
|
tok1 = tok1->tokAt(-2);
|
||||||
}
|
}
|
||||||
scopeInfo->emplace_back(scope, tok->link());
|
scopeInfo->emplace_back(scope, tok->link());
|
||||||
|
added = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (all && !added)
|
||||||
|
scopeInfo->emplace_back("", tok->link());
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2608,6 +2615,375 @@ void TemplateSimplifier::printOut(const std::string & text) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Token *findSemicolon(Token *tok)
|
||||||
|
{
|
||||||
|
unsigned int level = 0;
|
||||||
|
|
||||||
|
for (; tok && (level > 0 || tok->str() != ";"); tok = tok->next()) {
|
||||||
|
if (tok->str() == "{")
|
||||||
|
++level;
|
||||||
|
else if (level > 0 && tok->str() == "}")
|
||||||
|
--level;
|
||||||
|
}
|
||||||
|
|
||||||
|
return tok;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TemplateSimplifier::simplifyUsing()
|
||||||
|
{
|
||||||
|
bool substitute = false;
|
||||||
|
std::list<ScopeInfo2> scopeList;
|
||||||
|
bool inTemplateDefinition = false;
|
||||||
|
const Token *endOfTemplateDefinition = nullptr;
|
||||||
|
bool isVariable = false;
|
||||||
|
struct Using {
|
||||||
|
Using(Token *start, Token *end) : startTok(start), endTok(end) { }
|
||||||
|
Token *startTok;
|
||||||
|
Token *endTok;
|
||||||
|
};
|
||||||
|
std::list<Using> usingList;
|
||||||
|
|
||||||
|
scopeList.emplace_back("", nullptr);
|
||||||
|
|
||||||
|
for (Token *tok = mTokenList.front(); tok; tok = tok->next()) {
|
||||||
|
if (mErrorLogger && !mTokenList.getFiles().empty())
|
||||||
|
mErrorLogger->reportProgress(mTokenList.getFiles()[0], "Tokenize (using)", tok->progressValue());
|
||||||
|
|
||||||
|
if (mSettings->terminated())
|
||||||
|
return substitute;
|
||||||
|
|
||||||
|
if (Token::Match(tok, "{|}|namespace|class|struct|union") ||
|
||||||
|
Token::Match(tok, "using namespace %name% ;|::")) {
|
||||||
|
setScopeInfo(tok, &scopeList);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inTemplateDefinition) {
|
||||||
|
if (!endOfTemplateDefinition) {
|
||||||
|
if (isVariable)
|
||||||
|
endOfTemplateDefinition = findSemicolon(tok);
|
||||||
|
else if (tok->str() == "{")
|
||||||
|
endOfTemplateDefinition = tok->link();
|
||||||
|
}
|
||||||
|
if (tok == endOfTemplateDefinition) {
|
||||||
|
inTemplateDefinition = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tok->str()=="template") {
|
||||||
|
if (Token::Match(tok->next(), "< !!>"))
|
||||||
|
inTemplateDefinition = true;
|
||||||
|
else
|
||||||
|
inTemplateDefinition = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!inTemplateDefinition) {
|
||||||
|
// look for non-template type aliases
|
||||||
|
if (tok->strAt(-1) != ">" &&
|
||||||
|
(Token::Match(tok, "using %name% = ::| %name%") ||
|
||||||
|
(Token::Match(tok, "using %name% [ [") &&
|
||||||
|
Token::Match(tok->linkAt(2), "] ] = ::| %name%")))) {
|
||||||
|
std::list<ScopeInfo2> scopeList1;
|
||||||
|
scopeList1.emplace_back("", nullptr);
|
||||||
|
std::string name = tok->strAt(1);
|
||||||
|
const Token *nameToken = tok->next();
|
||||||
|
std::string scope = getScopeName(scopeList);
|
||||||
|
Token *usingStart = tok;
|
||||||
|
Token *start;
|
||||||
|
if (tok->strAt(2) == "=")
|
||||||
|
start = tok->tokAt(3);
|
||||||
|
else
|
||||||
|
start = tok->linkAt(2)->tokAt(3);
|
||||||
|
Token *usingEnd = findSemicolon(start);
|
||||||
|
if (!usingEnd)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Move struct defined in using out of using.
|
||||||
|
// using T = struct t { }; => struct t { }; using T = struct t;
|
||||||
|
// fixme: this doesn't handle attributes
|
||||||
|
if (Token::Match(start, "struct|union|enum %name%| {")) {
|
||||||
|
if (start->strAt(1) != "{") {
|
||||||
|
Token *structEnd = start->linkAt(2);
|
||||||
|
structEnd->insertToken(";", "");
|
||||||
|
mTokenList.copyTokens(structEnd->next(), tok, start->next());
|
||||||
|
usingStart = structEnd->tokAt(2);
|
||||||
|
nameToken = usingStart->next();
|
||||||
|
if (usingStart->strAt(2) == "=")
|
||||||
|
start = usingStart->tokAt(3);
|
||||||
|
else
|
||||||
|
start = usingStart->linkAt(2)->tokAt(3);
|
||||||
|
usingEnd = findSemicolon(start);
|
||||||
|
tok->deleteThis();
|
||||||
|
tok->deleteThis();
|
||||||
|
tok->deleteThis();
|
||||||
|
tok = usingStart;
|
||||||
|
} else {
|
||||||
|
Token *structEnd = start->linkAt(1);
|
||||||
|
structEnd->insertToken(";", "");
|
||||||
|
std::string newName;
|
||||||
|
if (structEnd->strAt(2) == ";")
|
||||||
|
newName = name;
|
||||||
|
else
|
||||||
|
newName = "Unnamed" + MathLib::toString(mTokenizer->mUnnamedCount++);
|
||||||
|
mTokenList.copyTokens(structEnd->next(), tok, start);
|
||||||
|
structEnd->tokAt(5)->insertToken(newName, "");
|
||||||
|
start->insertToken(newName, "");
|
||||||
|
|
||||||
|
usingStart = structEnd->tokAt(2);
|
||||||
|
nameToken = usingStart->next();
|
||||||
|
if (usingStart->strAt(2) == "=")
|
||||||
|
start = usingStart->tokAt(3);
|
||||||
|
else
|
||||||
|
start = usingStart->linkAt(2)->tokAt(3);
|
||||||
|
usingEnd = findSemicolon(start);
|
||||||
|
tok->deleteThis();
|
||||||
|
tok->deleteThis();
|
||||||
|
tok->deleteThis();
|
||||||
|
tok = usingStart;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unfortunately we have to start searching from the beginning
|
||||||
|
// of the token stream because templates are instantiated at
|
||||||
|
// the end of the token stream and it may be used before then.
|
||||||
|
std::string scope1;
|
||||||
|
bool skip = false; // don't erase type aliases we can't parse
|
||||||
|
for (Token* tok1 = mTokenList.front(); tok1; tok1 = tok1->next()) {
|
||||||
|
if ((Token::Match(tok1, "{|}|namespace|class|struct|union") && tok1->strAt(-1) != "using") ||
|
||||||
|
Token::Match(tok1, "using namespace %name% ;|::")) {
|
||||||
|
setScopeInfo(tok1, &scopeList1, true);
|
||||||
|
scope1 = getScopeName(scopeList1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (tok1 && tok1->str() == name) {
|
||||||
|
// skip this using
|
||||||
|
if (tok1 == nameToken) {
|
||||||
|
tok1 = findSemicolon(tok1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// skip other using with this name
|
||||||
|
if (tok1->strAt(-1) == "using") {
|
||||||
|
// fixme: this is wrong
|
||||||
|
// skip to end of scope
|
||||||
|
if (scopeList1.back().bodyEnd)
|
||||||
|
tok1 = scopeList1.back().bodyEnd->previous();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (Token::Match(tok1->tokAt(-1), "struct|union|enum")) {
|
||||||
|
// fixme
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get qualification
|
||||||
|
std::string qualification;
|
||||||
|
const Token* tok2 = tok1;
|
||||||
|
std::string::size_type index = scope.size();
|
||||||
|
std::string::size_type new_index = std::string::npos;
|
||||||
|
bool match = true;
|
||||||
|
while (tok2->strAt(-1) == "::") {
|
||||||
|
std::string last;
|
||||||
|
if (match && !scope1.empty()) {
|
||||||
|
new_index = scope1.rfind(' ', index - 1);
|
||||||
|
if (new_index != std::string::npos)
|
||||||
|
last = scope1.substr(new_index, index - new_index);
|
||||||
|
else if (!qualification.empty())
|
||||||
|
last.clear();
|
||||||
|
else
|
||||||
|
last = scope1;
|
||||||
|
} else
|
||||||
|
match = false;
|
||||||
|
if (match && tok2->strAt(-2) == last)
|
||||||
|
index = new_index;
|
||||||
|
else {
|
||||||
|
if (!qualification.empty())
|
||||||
|
qualification = " :: " + qualification;
|
||||||
|
qualification = tok2->strAt(-2) + qualification;
|
||||||
|
}
|
||||||
|
tok2 = tok2->tokAt(-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo: check using namespace
|
||||||
|
std::string fullScope1 = scope1;
|
||||||
|
if (!scope1.empty() && !qualification.empty())
|
||||||
|
fullScope1 += " :: ";
|
||||||
|
fullScope1 += qualification;
|
||||||
|
|
||||||
|
if (scope == fullScope1) {
|
||||||
|
// remove the qualification
|
||||||
|
while (tok1->strAt(-1) == "::" && tok1->strAt(-2) == scope) {
|
||||||
|
tok1->deletePrevious();
|
||||||
|
tok1->deletePrevious();
|
||||||
|
}
|
||||||
|
|
||||||
|
Token * arrayStart = nullptr;
|
||||||
|
|
||||||
|
// parse the type
|
||||||
|
Token *type = start;
|
||||||
|
if (type->str() == "::") {
|
||||||
|
type = type->next();
|
||||||
|
while (Token::Match(type, "%type% ::"))
|
||||||
|
type = type->tokAt(2);
|
||||||
|
if (Token::Match(type, "%type%"))
|
||||||
|
type = type->next();
|
||||||
|
} else if (Token::Match(type, "%type% ::")) {
|
||||||
|
do {
|
||||||
|
type = type->tokAt(2);
|
||||||
|
} while (Token::Match(type, "%type% ::"));
|
||||||
|
if (Token::Match(type, "%type%"))
|
||||||
|
type = type->next();
|
||||||
|
} else if (Token::Match(type, "%type%")) {
|
||||||
|
while (Token::Match(type, "const|struct|union|enum %type%") ||
|
||||||
|
(type->next() && type->next()->isStandardType()))
|
||||||
|
type = type->next();
|
||||||
|
|
||||||
|
type = type->next();
|
||||||
|
|
||||||
|
while (Token::Match(type, "%type%") &&
|
||||||
|
(type->isStandardType() || Token::Match(type, "unsigned|signed"))) {
|
||||||
|
type = type->next();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool atEnd = false;
|
||||||
|
while (!atEnd) {
|
||||||
|
if (type && type->str() == "::") {
|
||||||
|
type = type->next();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Token::Match(type, "%type%") &&
|
||||||
|
type->next() && !Token::Match(type->next(), "[|;|,|(")) {
|
||||||
|
type = type->next();
|
||||||
|
} else if (Token::simpleMatch(type, "const (")) {
|
||||||
|
type = type->next();
|
||||||
|
atEnd = true;
|
||||||
|
} else
|
||||||
|
atEnd = true;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
syntaxError(type);
|
||||||
|
|
||||||
|
// check for invalid input
|
||||||
|
if (!type)
|
||||||
|
syntaxError(tok1);
|
||||||
|
|
||||||
|
// check for template
|
||||||
|
if (type->str() == "<") {
|
||||||
|
type = type->findClosingBracket();
|
||||||
|
|
||||||
|
while (type && Token::Match(type->next(), ":: %type%"))
|
||||||
|
type = type->tokAt(2);
|
||||||
|
|
||||||
|
if (!type) {
|
||||||
|
syntaxError(tok1);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (Token::Match(type->next(), "const|volatile"))
|
||||||
|
type = type->next();
|
||||||
|
|
||||||
|
type = type->next();
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for pointers and references
|
||||||
|
std::list<std::string> pointers;
|
||||||
|
while (Token::Match(type, "*|&|&&|const")) {
|
||||||
|
pointers.push_back(type->str());
|
||||||
|
type = type->next();
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for array
|
||||||
|
if (type && type->str() == "[") {
|
||||||
|
do {
|
||||||
|
if (!arrayStart)
|
||||||
|
arrayStart = type;
|
||||||
|
|
||||||
|
bool atEnd = false;
|
||||||
|
while (!atEnd) {
|
||||||
|
while (type->next() && !Token::Match(type->next(), ";|,")) {
|
||||||
|
type = type->next();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!type->next())
|
||||||
|
syntaxError(type); // invalid input
|
||||||
|
else if (type->next()->str() == ";")
|
||||||
|
atEnd = true;
|
||||||
|
else if (type->str() == "]")
|
||||||
|
atEnd = true;
|
||||||
|
else
|
||||||
|
type = type->next();
|
||||||
|
}
|
||||||
|
|
||||||
|
type = type->next();
|
||||||
|
} while (type && type->str() == "[");
|
||||||
|
}
|
||||||
|
|
||||||
|
Token* after = tok1->next();
|
||||||
|
// check if type was parsed
|
||||||
|
if (type && type == usingEnd) {
|
||||||
|
// check for array syntax and add type around variable
|
||||||
|
if (arrayStart) {
|
||||||
|
if (Token::Match(tok1->next(), "%name%")) {
|
||||||
|
mTokenList.copyTokens(tok1->next(), arrayStart, usingEnd->previous());
|
||||||
|
mTokenList.copyTokens(tok1, start, arrayStart->previous());
|
||||||
|
tok1->deleteThis();
|
||||||
|
substitute = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// just replace simple type aliases
|
||||||
|
mTokenList.copyTokens(tok1, start, usingEnd->previous());
|
||||||
|
tok1->deleteThis();
|
||||||
|
substitute = true;
|
||||||
|
}
|
||||||
|
} 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(ErrorLogger::ErrorMessage(callstack, &mTokenList, Severity::debug, "debug",
|
||||||
|
|
||||||
|
"Failed to parse \'" + str + "\'. The checking continues anyway.", false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tok1 = after;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!skip)
|
||||||
|
usingList.emplace_back(usingStart, usingEnd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete all used type alias definitions
|
||||||
|
for (std::list<Using>::reverse_iterator it = usingList.rbegin(); it != usingList.rend(); ++it) {
|
||||||
|
Token *usingStart = it->startTok;
|
||||||
|
Token *usingEnd = it->endTok;
|
||||||
|
if (usingStart->previous()) {
|
||||||
|
if (usingEnd->next())
|
||||||
|
Token::eraseTokens(usingStart->previous(), usingEnd->next());
|
||||||
|
else {
|
||||||
|
Token::eraseTokens(usingStart, usingEnd);
|
||||||
|
usingEnd->deleteThis();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (usingEnd->next()) {
|
||||||
|
Token::eraseTokens(usingStart, usingEnd->next());
|
||||||
|
usingStart->deleteThis();
|
||||||
|
} else {
|
||||||
|
Token::eraseTokens(usingStart, usingEnd);
|
||||||
|
usingStart->deleteThis();
|
||||||
|
usingEnd->deleteThis();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return substitute;
|
||||||
|
}
|
||||||
|
|
||||||
void TemplateSimplifier::simplifyTemplates(
|
void TemplateSimplifier::simplifyTemplates(
|
||||||
const std::time_t maxtime,
|
const std::time_t maxtime,
|
||||||
bool &codeWithTemplates)
|
bool &codeWithTemplates)
|
||||||
|
@ -2619,7 +2995,12 @@ void TemplateSimplifier::simplifyTemplates(
|
||||||
// Unfortunately the template simplifier doesn't handle namespaces properly so
|
// Unfortunately the template simplifier doesn't handle namespaces properly so
|
||||||
// the uninstantiated template code in the symbol database can't be removed until #8768
|
// the uninstantiated template code in the symbol database can't be removed until #8768
|
||||||
// is fixed.
|
// is fixed.
|
||||||
|
|
||||||
for (int i = 0; i < 2; ++i) {
|
for (int i = 0; i < 2; ++i) {
|
||||||
|
// it may take more than one pass to simplify type aliases
|
||||||
|
while (simplifyUsing())
|
||||||
|
;
|
||||||
|
|
||||||
if (i) {
|
if (i) {
|
||||||
mTemplateDeclarations.clear();
|
mTemplateDeclarations.clear();
|
||||||
mTemplateForwardDeclarations.clear();
|
mTemplateForwardDeclarations.clear();
|
||||||
|
|
|
@ -384,6 +384,9 @@ private:
|
||||||
const std::string &indent = " ") const;
|
const std::string &indent = " ") const;
|
||||||
void printOut(const std::string &text = "") const;
|
void printOut(const std::string &text = "") const;
|
||||||
|
|
||||||
|
bool simplifyUsing();
|
||||||
|
|
||||||
|
Tokenizer *mTokenizer;
|
||||||
TokenList &mTokenList;
|
TokenList &mTokenList;
|
||||||
const Settings *mSettings;
|
const Settings *mSettings;
|
||||||
ErrorLogger *mErrorLogger;
|
ErrorLogger *mErrorLogger;
|
||||||
|
|
|
@ -8839,7 +8839,9 @@ void Tokenizer::simplifyStructDecl()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// check for anonymous enum
|
// check for anonymous enum
|
||||||
else if ((Token::simpleMatch(tok, "enum {") && Token::Match(tok->next()->link(), "} %type%| ,|;|[|(|{")) ||
|
else if ((Token::simpleMatch(tok, "enum {") &&
|
||||||
|
!Token::Match(tok->tokAt(-3), "using %name% =") &&
|
||||||
|
Token::Match(tok->next()->link(), "} %type%| ,|;|[|(|{")) ||
|
||||||
(Token::Match(tok, "enum : %type% {") && Token::Match(tok->linkAt(3), "} %type%| ,|;|[|(|{"))) {
|
(Token::Match(tok, "enum : %type% {") && Token::Match(tok->linkAt(3), "} %type%| ,|;|[|(|{"))) {
|
||||||
tok->insertToken("Anonymous" + MathLib::toString(count++));
|
tok->insertToken("Anonymous" + MathLib::toString(count++));
|
||||||
}
|
}
|
||||||
|
@ -8949,7 +8951,7 @@ void Tokenizer::simplifyStructDecl()
|
||||||
}
|
}
|
||||||
|
|
||||||
// don't remove unnamed anonymous unions from a class, struct or union
|
// don't remove unnamed anonymous unions from a class, struct or union
|
||||||
if (!(!inFunction && tok1->str() == "union")) {
|
if (!(!inFunction && tok1->str() == "union") && !Token::Match(tok1->tokAt(-3), "using %name% =")) {
|
||||||
skip.pop();
|
skip.pop();
|
||||||
tok1->deleteThis();
|
tok1->deleteThis();
|
||||||
if (tok1->next() == tok) {
|
if (tok1->next() == tok) {
|
||||||
|
|
|
@ -49,6 +49,7 @@ class CPPCHECKLIB Tokenizer {
|
||||||
|
|
||||||
friend class TestSimplifyTokens;
|
friend class TestSimplifyTokens;
|
||||||
friend class TestSimplifyTypedef;
|
friend class TestSimplifyTypedef;
|
||||||
|
friend class TestSimplifyUsing;
|
||||||
friend class TestTokenizer;
|
friend class TestTokenizer;
|
||||||
friend class SymbolDatabase;
|
friend class SymbolDatabase;
|
||||||
friend class TestSimplifyTemplate;
|
friend class TestSimplifyTemplate;
|
||||||
|
|
|
@ -42,6 +42,7 @@ SOURCES += $${BASEPATH}/test64bit.cpp \
|
||||||
$${BASEPATH}/testsimplifytemplate.cpp \
|
$${BASEPATH}/testsimplifytemplate.cpp \
|
||||||
$${BASEPATH}/testsimplifytokens.cpp \
|
$${BASEPATH}/testsimplifytokens.cpp \
|
||||||
$${BASEPATH}/testsimplifytypedef.cpp \
|
$${BASEPATH}/testsimplifytypedef.cpp \
|
||||||
|
$${BASEPATH}/testsimplifyusing.cpp \
|
||||||
$${BASEPATH}/testsizeof.cpp \
|
$${BASEPATH}/testsizeof.cpp \
|
||||||
$${BASEPATH}/teststl.cpp \
|
$${BASEPATH}/teststl.cpp \
|
||||||
$${BASEPATH}/teststring.cpp \
|
$${BASEPATH}/teststring.cpp \
|
||||||
|
|
|
@ -69,6 +69,7 @@
|
||||||
<ClCompile Include="testsimplifytemplate.cpp" />
|
<ClCompile Include="testsimplifytemplate.cpp" />
|
||||||
<ClCompile Include="testsimplifytokens.cpp" />
|
<ClCompile Include="testsimplifytokens.cpp" />
|
||||||
<ClCompile Include="testsimplifytypedef.cpp" />
|
<ClCompile Include="testsimplifytypedef.cpp" />
|
||||||
|
<ClCompile Include="testsimplifyusing.cpp" />
|
||||||
<ClCompile Include="testsizeof.cpp" />
|
<ClCompile Include="testsizeof.cpp" />
|
||||||
<ClCompile Include="teststl.cpp" />
|
<ClCompile Include="teststl.cpp" />
|
||||||
<ClCompile Include="teststring.cpp" />
|
<ClCompile Include="teststring.cpp" />
|
||||||
|
|
|
@ -136,6 +136,7 @@ private:
|
||||||
TEST_CASE(template96); // #7854
|
TEST_CASE(template96); // #7854
|
||||||
TEST_CASE(template97);
|
TEST_CASE(template97);
|
||||||
TEST_CASE(template98); // #8959
|
TEST_CASE(template98); // #8959
|
||||||
|
TEST_CASE(template99); // #8960
|
||||||
TEST_CASE(template_specialization_1); // #7868 - template specialization template <typename T> struct S<C<T>> {..};
|
TEST_CASE(template_specialization_1); // #7868 - template specialization template <typename T> struct S<C<T>> {..};
|
||||||
TEST_CASE(template_specialization_2); // #7868 - template specialization template <typename T> struct S<C<T>> {..};
|
TEST_CASE(template_specialization_2); // #7868 - template specialization template <typename T> struct S<C<T>> {..};
|
||||||
TEST_CASE(template_enum); // #6299 Syntax error in complex enum declaration (including template)
|
TEST_CASE(template_enum); // #6299 Syntax error in complex enum declaration (including template)
|
||||||
|
@ -2083,6 +2084,23 @@ private:
|
||||||
ASSERT_EQUALS(exp, tok(code));
|
ASSERT_EQUALS(exp, tok(code));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void template99() { // #8960
|
||||||
|
const char code[] = "template <typename T>\n"
|
||||||
|
"class Base {\n"
|
||||||
|
"public:\n"
|
||||||
|
" using ArrayType = std::vector<Base<T>>;\n"
|
||||||
|
"};\n"
|
||||||
|
"using A = Base<int>;\n"
|
||||||
|
"static A::ArrayType array;\n";
|
||||||
|
const char exp[] = "class Base<int> ; "
|
||||||
|
"static std :: vector < Base<int> > array ; "
|
||||||
|
"class Base<int> { "
|
||||||
|
"public: "
|
||||||
|
"} ;";
|
||||||
|
|
||||||
|
ASSERT_EQUALS(exp, tok(code));
|
||||||
|
}
|
||||||
|
|
||||||
void template_specialization_1() { // #7868 - template specialization template <typename T> struct S<C<T>> {..};
|
void template_specialization_1() { // #7868 - template specialization template <typename T> struct S<C<T>> {..};
|
||||||
const char code[] = "template <typename T> struct C {};\n"
|
const char code[] = "template <typename T> struct C {};\n"
|
||||||
"template <typename T> struct S {a};\n"
|
"template <typename T> struct S {a};\n"
|
||||||
|
|
|
@ -0,0 +1,417 @@
|
||||||
|
/*
|
||||||
|
* Cppcheck - A tool for static C/C++ code analysis
|
||||||
|
* Copyright (C) 2007-2018 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 "platform.h"
|
||||||
|
#include "settings.h"
|
||||||
|
#include "testsuite.h"
|
||||||
|
#include "token.h"
|
||||||
|
#include "tokenize.h"
|
||||||
|
#include "tokenlist.h"
|
||||||
|
|
||||||
|
struct InternalError;
|
||||||
|
|
||||||
|
|
||||||
|
class TestSimplifyUsing : public TestFixture {
|
||||||
|
public:
|
||||||
|
TestSimplifyUsing() : TestFixture("TestSimplifyUsing") {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
Settings settings0;
|
||||||
|
Settings settings1;
|
||||||
|
Settings settings2;
|
||||||
|
|
||||||
|
void run() OVERRIDE {
|
||||||
|
settings0.addEnabled("style");
|
||||||
|
settings2.addEnabled("style");
|
||||||
|
|
||||||
|
TEST_CASE(simplifyUsing1);
|
||||||
|
TEST_CASE(simplifyUsing2);
|
||||||
|
TEST_CASE(simplifyUsing3);
|
||||||
|
TEST_CASE(simplifyUsing4);
|
||||||
|
TEST_CASE(simplifyUsing5);
|
||||||
|
TEST_CASE(simplifyUsing6);
|
||||||
|
TEST_CASE(simplifyUsing7);
|
||||||
|
TEST_CASE(simplifyUsing8);
|
||||||
|
TEST_CASE(simplifyUsing9);
|
||||||
|
TEST_CASE(simplifyUsing10);
|
||||||
|
TEST_CASE(simplifyUsing11);
|
||||||
|
TEST_CASE(simplifyUsing12);
|
||||||
|
TEST_CASE(simplifyUsing13);
|
||||||
|
TEST_CASE(simplifyUsing14);
|
||||||
|
TEST_CASE(simplifyUsing15);
|
||||||
|
TEST_CASE(simplifyUsing16);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string tok(const char code[], bool simplify = true, Settings::PlatformType type = Settings::Native, bool debugwarnings = true) {
|
||||||
|
errout.str("");
|
||||||
|
|
||||||
|
settings0.inconclusive = true;
|
||||||
|
settings0.debugwarnings = debugwarnings;
|
||||||
|
settings0.platform(type);
|
||||||
|
Tokenizer tokenizer(&settings0, this);
|
||||||
|
|
||||||
|
std::istringstream istr(code);
|
||||||
|
tokenizer.tokenize(istr, "test.cpp");
|
||||||
|
|
||||||
|
if (simplify)
|
||||||
|
tokenizer.simplifyTokenList2();
|
||||||
|
|
||||||
|
return tokenizer.tokens()->stringifyList(0, !simplify);
|
||||||
|
}
|
||||||
|
|
||||||
|
void simplifyUsing1() {
|
||||||
|
const char code[] = "class A\n"
|
||||||
|
"{\n"
|
||||||
|
"public:\n"
|
||||||
|
" using duplicate = wchar_t;\n"
|
||||||
|
" void foo() {}\n"
|
||||||
|
"};\n"
|
||||||
|
"using duplicate = A;\n"
|
||||||
|
"int main()\n"
|
||||||
|
"{\n"
|
||||||
|
" duplicate a;\n"
|
||||||
|
" a.foo();\n"
|
||||||
|
" A::duplicate c = 0;\n"
|
||||||
|
"}";
|
||||||
|
|
||||||
|
const char expected[] =
|
||||||
|
"class A "
|
||||||
|
"{ "
|
||||||
|
"public: "
|
||||||
|
""
|
||||||
|
"void foo ( ) { } "
|
||||||
|
"} ; "
|
||||||
|
"int main ( ) "
|
||||||
|
"{ "
|
||||||
|
"A a ; "
|
||||||
|
"a . foo ( ) ; "
|
||||||
|
"wchar_t c ; c = 0 ; "
|
||||||
|
"}";
|
||||||
|
ASSERT_EQUALS(expected, tok(code, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
void simplifyUsing2() {
|
||||||
|
const char code[] = "class A;\n"
|
||||||
|
"using duplicate = A;\n"
|
||||||
|
"class A\n"
|
||||||
|
"{\n"
|
||||||
|
"public:\n"
|
||||||
|
"using duplicate = wchar_t;\n"
|
||||||
|
"duplicate foo() { wchar_t b; return b; }\n"
|
||||||
|
"};";
|
||||||
|
|
||||||
|
const char expected[] =
|
||||||
|
"class A ; "
|
||||||
|
"class A "
|
||||||
|
"{ "
|
||||||
|
"public: "
|
||||||
|
""
|
||||||
|
"wchar_t foo ( ) { wchar_t b ; return b ; } "
|
||||||
|
"} ;";
|
||||||
|
ASSERT_EQUALS(expected, tok(code));
|
||||||
|
}
|
||||||
|
|
||||||
|
void simplifyUsing3() {
|
||||||
|
const char code[] = "class A {};\n"
|
||||||
|
"using duplicate = A;\n"
|
||||||
|
"wchar_t foo()\n"
|
||||||
|
"{\n"
|
||||||
|
"using duplicate = wchar_t;\n"
|
||||||
|
"duplicate b;\n"
|
||||||
|
"return b;\n"
|
||||||
|
"}\n"
|
||||||
|
"int main()\n"
|
||||||
|
"{\n"
|
||||||
|
"duplicate b;\n"
|
||||||
|
"}";
|
||||||
|
|
||||||
|
const char expected[] =
|
||||||
|
"class A { } ; "
|
||||||
|
"wchar_t foo ( ) "
|
||||||
|
"{ "
|
||||||
|
""
|
||||||
|
"wchar_t b ; "
|
||||||
|
"return b ; "
|
||||||
|
"} "
|
||||||
|
"int main ( ) "
|
||||||
|
"{ "
|
||||||
|
"A b ; "
|
||||||
|
"}";
|
||||||
|
ASSERT_EQUALS(expected, tok(code));
|
||||||
|
}
|
||||||
|
|
||||||
|
void simplifyUsing4() {
|
||||||
|
const char code[] = "using s32 = int;\n"
|
||||||
|
"using u32 = unsigned int;\n"
|
||||||
|
"void f()\n"
|
||||||
|
"{\n"
|
||||||
|
" s32 ivar = -2;\n"
|
||||||
|
" u32 uvar = 2;\n"
|
||||||
|
" return uvar / ivar;\n"
|
||||||
|
"}";
|
||||||
|
|
||||||
|
const char expected[] =
|
||||||
|
"void f ( ) "
|
||||||
|
"{ "
|
||||||
|
"int ivar ; ivar = -2 ; "
|
||||||
|
"unsigned int uvar ; uvar = 2 ; "
|
||||||
|
"return uvar / ivar ; "
|
||||||
|
"}";
|
||||||
|
ASSERT_EQUALS(expected, tok(code, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
void simplifyUsing5() {
|
||||||
|
const char code[] =
|
||||||
|
"using YY_BUFFER_STATE = struct yy_buffer_state *;\n"
|
||||||
|
"void f()\n"
|
||||||
|
"{\n"
|
||||||
|
" YY_BUFFER_STATE state;\n"
|
||||||
|
"}";
|
||||||
|
|
||||||
|
const char expected[] =
|
||||||
|
"void f ( ) "
|
||||||
|
"{ "
|
||||||
|
"struct yy_buffer_state * state ; "
|
||||||
|
"}";
|
||||||
|
|
||||||
|
ASSERT_EQUALS(expected, tok(code, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
void simplifyUsing6() {
|
||||||
|
const char code[] =
|
||||||
|
"namespace VL {\n"
|
||||||
|
" using float_t = float;\n"
|
||||||
|
" inline VL::float_t fast_atan2(VL::float_t y, VL::float_t x){}\n"
|
||||||
|
"}";
|
||||||
|
|
||||||
|
const char expected[] =
|
||||||
|
"namespace VL { "
|
||||||
|
""
|
||||||
|
"float fast_atan2 ( float y , float x ) { } "
|
||||||
|
"}";
|
||||||
|
|
||||||
|
ASSERT_EQUALS(expected, tok(code, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
void simplifyUsing7() {
|
||||||
|
const char code[] = "using abc = int; "
|
||||||
|
"Fred :: abc f ;";
|
||||||
|
const char expected[] = "Fred :: abc f ;";
|
||||||
|
ASSERT_EQUALS(expected, tok(code, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
void simplifyUsing8() {
|
||||||
|
const char code[] = "using INT = int;\n"
|
||||||
|
"using UINT = unsigned int;\n"
|
||||||
|
"using PINT = int *;\n"
|
||||||
|
"using PUINT = unsigned int *;\n"
|
||||||
|
"using RINT = int &;\n"
|
||||||
|
"using RUINT = unsigned int &;\n"
|
||||||
|
"using RCINT = const int &;\n"
|
||||||
|
"using RCUINT = const unsigned int &;\n"
|
||||||
|
"INT ti;\n"
|
||||||
|
"UINT tui;\n"
|
||||||
|
"PINT tpi;\n"
|
||||||
|
"PUINT tpui;\n"
|
||||||
|
"RINT tri;\n"
|
||||||
|
"RUINT trui;\n"
|
||||||
|
"RCINT trci;\n"
|
||||||
|
"RCUINT trcui;";
|
||||||
|
|
||||||
|
const char expected[] =
|
||||||
|
"int ti ; "
|
||||||
|
"unsigned int tui ; "
|
||||||
|
"int * tpi ; "
|
||||||
|
"unsigned int * tpui ; "
|
||||||
|
"int & tri ; "
|
||||||
|
"unsigned int & trui ; "
|
||||||
|
"const int & trci ; "
|
||||||
|
"const unsigned int & trcui ;";
|
||||||
|
|
||||||
|
ASSERT_EQUALS(expected, tok(code, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
void simplifyUsing9() {
|
||||||
|
const char code[] = "using S = struct s;\n"
|
||||||
|
"using PS = S *;\n"
|
||||||
|
"using T = struct t { int a; };\n"
|
||||||
|
"using TP = T *;\n"
|
||||||
|
"using U = struct { int a; };\n"
|
||||||
|
"using V = U *;\n"
|
||||||
|
"using W = struct { int a; } *;\n"
|
||||||
|
"S s;\n"
|
||||||
|
"PS ps;\n"
|
||||||
|
"T t;\n"
|
||||||
|
"TP tp;\n"
|
||||||
|
"U u;\n"
|
||||||
|
"V v;\n"
|
||||||
|
"W w;";
|
||||||
|
|
||||||
|
const char expected[] =
|
||||||
|
"struct t { int a ; } ; "
|
||||||
|
"struct U { int a ; } ; "
|
||||||
|
"struct Unnamed0 { int a ; } ; "
|
||||||
|
"struct s s ; "
|
||||||
|
"struct s * ps ; "
|
||||||
|
"struct t t ; "
|
||||||
|
"struct t * tp ; "
|
||||||
|
"struct U u ; "
|
||||||
|
"struct U * v ; "
|
||||||
|
"struct Unnamed0 * w ;";
|
||||||
|
|
||||||
|
ASSERT_EQUALS(expected, tok(code, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
void simplifyUsing10() {
|
||||||
|
const char code[] = "using S = union s;\n"
|
||||||
|
"using PS = S *;\n"
|
||||||
|
"using T = union t { int a; float b ; };\n"
|
||||||
|
"using TP = T *;\n"
|
||||||
|
"using U = union { int a; float b; };\n"
|
||||||
|
"using V = U *;\n"
|
||||||
|
"using W = union { int a; float b; } *;\n"
|
||||||
|
"S s;\n"
|
||||||
|
"PS ps;\n"
|
||||||
|
"T t;\n"
|
||||||
|
"TP tp;\n"
|
||||||
|
"U u;\n"
|
||||||
|
"V v;\n"
|
||||||
|
"W w;";
|
||||||
|
|
||||||
|
const char expected[] =
|
||||||
|
"union t { int a ; float b ; } ; "
|
||||||
|
"union U { int a ; float b ; } ; "
|
||||||
|
"union Unnamed0 { int a ; float b ; } ; "
|
||||||
|
"union s s ; "
|
||||||
|
"union s * ps ; "
|
||||||
|
"union t t ; "
|
||||||
|
"union t * tp ; "
|
||||||
|
"union U u ; "
|
||||||
|
"union U * v ; "
|
||||||
|
"union Unnamed0 * w ;";
|
||||||
|
|
||||||
|
ASSERT_EQUALS(expected, tok(code, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
void simplifyUsing11() {
|
||||||
|
const char code[] = "using abc = enum { a = 0 , b = 1 , c = 2 };\n"
|
||||||
|
"using XYZ = enum xyz { x = 0 , y = 1 , z = 2 };\n"
|
||||||
|
"abc e1;\n"
|
||||||
|
"XYZ e2;";
|
||||||
|
|
||||||
|
const char expected[] = "enum abc { a = 0 , b = 1 , c = 2 } ; "
|
||||||
|
"enum xyz { x = 0 , y = 1 , z = 2 } ; "
|
||||||
|
"enum abc e1 ; "
|
||||||
|
"enum xyz e2 ;";
|
||||||
|
|
||||||
|
ASSERT_EQUALS(expected, tok(code, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
void simplifyUsing12() {
|
||||||
|
const char code[] = "using V1 = vector<int>;\n"
|
||||||
|
"using V2 = std::vector<int>;\n"
|
||||||
|
"using V3 = std::vector<std::vector<int> >;\n"
|
||||||
|
"using IntListIterator = std::list<int>::iterator;\n"
|
||||||
|
"V1 v1;\n"
|
||||||
|
"V2 v2;\n"
|
||||||
|
"V3 v3;\n"
|
||||||
|
"IntListIterator iter;";
|
||||||
|
|
||||||
|
const char expected[] = "vector < int > v1 ; "
|
||||||
|
"std :: vector < int > v2 ; "
|
||||||
|
"std :: vector < std :: vector < int > > v3 ; "
|
||||||
|
"std :: list < int > :: iterator iter ;";
|
||||||
|
|
||||||
|
ASSERT_EQUALS(expected, tok(code, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
void simplifyUsing13() {
|
||||||
|
const char code[] = "using Func = std::pair<int(*)(void*), void*>;\n"
|
||||||
|
"using CallQueue = std::vector<Func>;\n"
|
||||||
|
"int main() {\n"
|
||||||
|
" CallQueue q;\n"
|
||||||
|
"}";
|
||||||
|
|
||||||
|
const char expected[] = "int main ( ) { "
|
||||||
|
"std :: vector < std :: pair < int ( * ) ( void * ) , void * > > q ; "
|
||||||
|
"}";
|
||||||
|
|
||||||
|
ASSERT_EQUALS(expected, tok(code, false));
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void simplifyUsing14() {
|
||||||
|
const char code[] = "template <typename F, unsigned int N> struct E"
|
||||||
|
"{"
|
||||||
|
" using v = E<F,(N>0)?(N-1):0>;"
|
||||||
|
" using val = typename add<v,v>::val;"
|
||||||
|
" FP_M(val);"
|
||||||
|
"};"
|
||||||
|
"template <typename F> struct E <F,0>"
|
||||||
|
"{"
|
||||||
|
" using nal = typename D<1>::val;"
|
||||||
|
" FP_M(val);"
|
||||||
|
"};";
|
||||||
|
|
||||||
|
tok(code, true, Settings::Native, false);
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void simplifyUsing15() {
|
||||||
|
{
|
||||||
|
const char code[] = "using frame = char [10];\n"
|
||||||
|
"frame f;";
|
||||||
|
|
||||||
|
const char expected[] = "char f [ 10 ] ;";
|
||||||
|
|
||||||
|
ASSERT_EQUALS(expected, tok(code, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const char code[] = "using frame = unsigned char [10];\n"
|
||||||
|
"frame f;";
|
||||||
|
|
||||||
|
const char expected[] = "unsigned char f [ 10 ] ;";
|
||||||
|
|
||||||
|
ASSERT_EQUALS(expected, tok(code, false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void simplifyUsing16() {
|
||||||
|
const char code[] = "using MOT8 = char;\n"
|
||||||
|
"using CHFOO = MOT8 [4096];\n"
|
||||||
|
"using STRFOO = struct {\n"
|
||||||
|
" CHFOO freem;\n"
|
||||||
|
"};\n"
|
||||||
|
"STRFOO s;";
|
||||||
|
|
||||||
|
const char expected[] = "struct STRFOO { "
|
||||||
|
"char freem [ 4096 ] ; "
|
||||||
|
"} ; "
|
||||||
|
"struct STRFOO s ;";
|
||||||
|
|
||||||
|
ASSERT_EQUALS(expected, tok(code, false));
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
REGISTER_TEST(TestSimplifyUsing)
|
|
@ -382,12 +382,6 @@ private:
|
||||||
TEST_CASE(auto10); // #8020
|
TEST_CASE(auto10); // #8020
|
||||||
|
|
||||||
TEST_CASE(unionWithConstructor);
|
TEST_CASE(unionWithConstructor);
|
||||||
|
|
||||||
TEST_CASE(using1);
|
|
||||||
TEST_CASE(using2); // #8331 (segmentation fault)
|
|
||||||
TEST_CASE(using3); // #8343 (segmentation fault)
|
|
||||||
TEST_CASE(using4); // #8952 (unknown type)
|
|
||||||
TEST_CASE(using5); // #8950 (couldn't resolve all user defined types)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void array() {
|
void array() {
|
||||||
|
@ -6806,138 +6800,6 @@ private:
|
||||||
f = Token::findsimplematch(tokenizer.tokens(), "Fred ( float");
|
f = Token::findsimplematch(tokenizer.tokens(), "Fred ( float");
|
||||||
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 3);
|
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
void using1() {
|
|
||||||
const Standards::cppstd_t original_std = settings1.standards.cpp;
|
|
||||||
settings1.standards.cpp = Standards::CPP11;
|
|
||||||
GET_SYMBOL_DB("using INT = int;\n"
|
|
||||||
"using PINT = INT *;\n"
|
|
||||||
"using PCINT = const PINT;\n"
|
|
||||||
"INT i;\n"
|
|
||||||
"PINT pi;\n"
|
|
||||||
"PCINT pci;");
|
|
||||||
settings1.standards.cpp = original_std;
|
|
||||||
const Token *tok = Token::findsimplematch(tokenizer.tokens(), "INT i ;");
|
|
||||||
|
|
||||||
ASSERT(db && tok && tok->next() && tok->next()->valueType());
|
|
||||||
if (db && tok && tok->next() && tok->next()->valueType()) {
|
|
||||||
tok = tok->next();
|
|
||||||
ASSERT_EQUALS(0, tok->valueType()->constness);
|
|
||||||
ASSERT_EQUALS(0, tok->valueType()->pointer);
|
|
||||||
ASSERT_EQUALS(ValueType::SIGNED, tok->valueType()->sign);
|
|
||||||
ASSERT_EQUALS(ValueType::INT, tok->valueType()->type);
|
|
||||||
}
|
|
||||||
|
|
||||||
tok = Token::findsimplematch(tokenizer.tokens(), "PINT pi ;");
|
|
||||||
|
|
||||||
ASSERT(db && tok && tok->next() && tok->next()->valueType());
|
|
||||||
if (db && tok && tok->next() && tok->next()->valueType()) {
|
|
||||||
tok = tok->next();
|
|
||||||
ASSERT_EQUALS(0, tok->valueType()->constness);
|
|
||||||
ASSERT_EQUALS(1, tok->valueType()->pointer);
|
|
||||||
ASSERT_EQUALS(ValueType::SIGNED, tok->valueType()->sign);
|
|
||||||
ASSERT_EQUALS(ValueType::INT, tok->valueType()->type);
|
|
||||||
}
|
|
||||||
|
|
||||||
tok = Token::findsimplematch(tokenizer.tokens(), "PCINT pci ;");
|
|
||||||
|
|
||||||
ASSERT(db && tok && tok->next() && tok->next()->valueType());
|
|
||||||
if (db && tok && tok->next() && tok->next()->valueType()) {
|
|
||||||
tok = tok->next();
|
|
||||||
ASSERT_EQUALS(1, tok->valueType()->constness);
|
|
||||||
ASSERT_EQUALS(1, tok->valueType()->pointer);
|
|
||||||
ASSERT_EQUALS(ValueType::SIGNED, tok->valueType()->sign);
|
|
||||||
ASSERT_EQUALS(ValueType::INT, tok->valueType()->type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void using2() { // #8331 (segmentation fault)
|
|
||||||
const Standards::cppstd_t original_std = settings1.standards.cpp;
|
|
||||||
settings1.standards.cpp = Standards::CPP11;
|
|
||||||
|
|
||||||
{
|
|
||||||
GET_SYMBOL_DB("using pboolean = pboolean;\n"
|
|
||||||
"pboolean b;");
|
|
||||||
const Token *tok = Token::findsimplematch(tokenizer.tokens(), "b ;");
|
|
||||||
|
|
||||||
ASSERT(db && tok && !tok->valueType());
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
GET_SYMBOL_DB("using pboolean = bool;\n"
|
|
||||||
"using pboolean = pboolean;\n"
|
|
||||||
"pboolean b;");
|
|
||||||
const Token *tok = Token::findsimplematch(tokenizer.tokens(), "b ;");
|
|
||||||
|
|
||||||
ASSERT(db && tok && tok->valueType());
|
|
||||||
if (db && tok && tok->valueType()) {
|
|
||||||
ASSERT_EQUALS(0, tok->valueType()->constness);
|
|
||||||
ASSERT_EQUALS(0, tok->valueType()->pointer);
|
|
||||||
ASSERT_EQUALS(ValueType::UNKNOWN_SIGN, tok->valueType()->sign);
|
|
||||||
ASSERT_EQUALS(ValueType::BOOL, tok->valueType()->type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
settings1.standards.cpp = original_std;
|
|
||||||
}
|
|
||||||
|
|
||||||
void using3() { // #8343 (segmentation fault)
|
|
||||||
const Standards::cppstd_t original_std = settings1.standards.cpp;
|
|
||||||
settings1.standards.cpp = Standards::CPP11;
|
|
||||||
GET_SYMBOL_DB("template <typename T>\n"
|
|
||||||
"using vector = typename MemoryModel::template vector<T>;\n"
|
|
||||||
"vector<uninitialized_uint64> m_bits;");
|
|
||||||
settings1.standards.cpp = original_std;
|
|
||||||
|
|
||||||
ASSERT(db != nullptr);
|
|
||||||
ASSERT_EQUALS("", errout.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
void using4() { // #8952 (unknown type)
|
|
||||||
const Standards::cppstd_t original_std = settings1.standards.cpp;
|
|
||||||
settings1.standards.cpp = Standards::CPP11;
|
|
||||||
settings1.debugwarnings = true;
|
|
||||||
GET_SYMBOL_DB("class A {\n"
|
|
||||||
"public:\n"
|
|
||||||
" enum Type { Null };\n"
|
|
||||||
"};\n"
|
|
||||||
"using V = A;\n"
|
|
||||||
"V::Type value;");
|
|
||||||
settings1.standards.cpp = original_std;
|
|
||||||
settings1.debugwarnings = false;
|
|
||||||
|
|
||||||
vartok = Token::findsimplematch(tokenizer.tokens(), "value");
|
|
||||||
ASSERT(db && vartok && vartok->valueType());
|
|
||||||
if (db && vartok && vartok->valueType()) {
|
|
||||||
ASSERT_EQUALS(0, vartok->valueType()->constness);
|
|
||||||
ASSERT_EQUALS(0, vartok->valueType()->pointer);
|
|
||||||
ASSERT_EQUALS(ValueType::SIGNED, vartok->valueType()->sign);
|
|
||||||
ASSERT_EQUALS(ValueType::INT, vartok->valueType()->type);
|
|
||||||
const Variable *var = vartok->variable();
|
|
||||||
ASSERT(var && var->type() && var->type()->isEnumType());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void using5() { // #8950 (couldn't resolve all user defined types)
|
|
||||||
const Standards::cppstd_t original_std = settings1.standards.cpp;
|
|
||||||
settings1.standards.cpp = Standards::CPP11;
|
|
||||||
settings1.debugwarnings = true;
|
|
||||||
GET_SYMBOL_DB("class A {\n"
|
|
||||||
"public:\n"
|
|
||||||
" using MapType = std::map<std::string, std::string>;\n"
|
|
||||||
"private:\n"
|
|
||||||
" MapType m;\n"
|
|
||||||
"};");
|
|
||||||
settings1.standards.cpp = original_std;
|
|
||||||
settings1.debugwarnings = false;
|
|
||||||
|
|
||||||
ASSERT_EQUALS("", errout.str());
|
|
||||||
ASSERT(db && db->scopeList.size() == 2); // global + class
|
|
||||||
if (db && db->scopeList.size() == 2) {
|
|
||||||
const Scope *scope = &db->scopeList.back();
|
|
||||||
ASSERT(scope->type == Scope::eClass && scope->definedType && scope->definedType->needInitialization == Type::False);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
REGISTER_TEST(TestSymbolDatabase)
|
REGISTER_TEST(TestSymbolDatabase)
|
||||||
|
|
Loading…
Reference in New Issue