Add support for simple c++ 11 type ailases like: using INT = int; (#1024)

* Add support for simple c++ 11 type ailases like: using INT = int;

Only types supported by ValueType are supported. Complex types like
function pointers are not supported. Template type aliases are not
supported.

* Fix crash when type in using type alias is simplified away.

This fixes a crash when size_t is replaced with unsigned long in: using
size_t = unsigned long; by the tokenizer.

This does not fix the problem where Tokenizer::simplifyPlatformTypes()
simplifies away size_t in other cases.  This is only a problem when the
new type is different from the platform type.
This commit is contained in:
IOBYTE 2018-01-10 16:16:18 -05:00 committed by Daniel Marjamäki
parent 58034dee86
commit cefb2131c7
4 changed files with 102 additions and 6 deletions

View File

@ -276,6 +276,21 @@ void SymbolDatabase::createSymbolDatabaseFindAllScopes()
tok = tok->tokAt(2);
}
// using type alias
else if (_tokenizer->isCPP() && Token::Match(tok, "using %name% =")) {
if (!findType(tok->next(), scope)) {
// fill typeList..
typeList.push_back(Type(tok, nullptr, scope));
Type* new_type = &typeList.back();
scope->definedTypesMap[new_type->name()] = new_type;
}
tok = tok->tokAt(3);
while (tok && tok->str() != ";")
tok = tok->next();
}
// unnamed struct and union
else if (Token::Match(tok, "struct|union {") &&
Token::Match(tok->next()->link(), "} *|&| %name% ;|[")) {
@ -3517,7 +3532,14 @@ static const Token* skipPointers(const Token* tok)
bool Scope::isVariableDeclaration(const Token* const tok, const Token*& vartok, const Token*& typetok) const
{
if (check && check->_tokenizer->isCPP() && Token::Match(tok, "throw|new"))
const bool isCPP = check && check->_tokenizer->isCPP();
if (isCPP && Token::Match(tok, "throw|new"))
return false;
const bool isCPP11 = isCPP && check->_settings->standards.cpp >= Standards::CPP11;
if (isCPP11 && tok->str() == "using")
return false;
const Token* localTypeTok = skipScopeIdentifiers(tok);
@ -4986,7 +5008,10 @@ static const Token * parsedecl(const Token *type, ValueType * const valuetype, V
valuetype->sign = ValueType::Sign::SIGNED;
else if (type->isUnsigned())
valuetype->sign = ValueType::Sign::UNSIGNED;
if (type->str() == "const")
if (valuetype->type == ValueType::Type::UNKNOWN_TYPE &&
type->type() && type->type()->isTypeAlias() && type->type()->typeStart)
parsedecl(type->type()->typeStart, valuetype, defaultSignedness, settings);
else if (type->str() == "const")
valuetype->constness |= (1 << (valuetype->pointer - pointer0));
else if (const Library::Container *container = settings->library.detectContainer(type)) {
valuetype->type = ValueType::Type::CONTAINER;

View File

@ -100,13 +100,24 @@ public:
std::vector<BaseInfo> derivedFrom;
std::list<FriendInfo> friendList;
const Token * typeStart;
const Token * typeEnd;
Type(const Token* classDef_ = nullptr, const Scope* classScope_ = nullptr, const Scope* enclosingScope_ = nullptr) :
classDef(classDef_),
classScope(classScope_),
enclosingScope(enclosingScope_),
needInitialization(Unknown) {
needInitialization(Unknown),
typeStart(nullptr),
typeEnd(nullptr) {
if (classDef_ && classDef_->str() == "enum")
needInitialization = True;
else if (classDef_ && classDef_->str() == "using") {
typeStart = classDef->tokAt(3);
typeEnd = typeStart;
while (typeEnd->next() && typeEnd->next()->str() != ";")
typeEnd = typeEnd->next();
}
}
const std::string& name() const;
@ -123,6 +134,10 @@ public:
return classDef && classDef->str() == "enum";
}
bool isTypeAlias() const {
return classDef && classDef->str() == "using";
}
bool isStructType() const {
return classDef && classDef->str() == "struct";
}

View File

@ -5538,6 +5538,8 @@ void Tokenizer::simplifyVarDecl(const bool only_k_r_fpar)
void Tokenizer::simplifyVarDecl(Token * tokBegin, const Token * const tokEnd, const bool only_k_r_fpar)
{
const bool isCPP11 = _settings->standards.cpp >= Standards::CPP11;
// Split up variable declarations..
// "int a=4;" => "int a; a=4;"
bool finishedwithkr = true;
@ -5586,6 +5588,8 @@ void Tokenizer::simplifyVarDecl(Token * tokBegin, const Token * const tokEnd, co
continue;
if (Token::Match(type0, "else|return|public:|protected:|private:"))
continue;
if (isCPP11 && type0->str() == "using")
continue;
bool isconst = false;
bool isstatic = false;
@ -5828,6 +5832,8 @@ void Tokenizer::simplifyVarDecl(Token * tokBegin, const Token * const tokEnd, co
void Tokenizer::simplifyPlatformTypes()
{
const bool isCPP11 = _settings->standards.cpp >= Standards::CPP11;
enum { isLongLong, isLong, isInt } type;
/** @todo This assumes a flat address space. Not true for segmented address space (FAR *). */
@ -5846,11 +5852,15 @@ void Tokenizer::simplifyPlatformTypes()
if (!Token::Match(tok, "std| ::| %type%"))
continue;
bool isUnsigned;
if (Token::Match(tok, "std| ::| size_t|uintptr_t|uintmax_t"))
if (Token::Match(tok, "std| ::| size_t|uintptr_t|uintmax_t")) {
if (isCPP11 && tok->strAt(-1) == "using" && tok->strAt(1) == "=")
continue;
isUnsigned = true;
else if (Token::Match(tok, "std| ::| ssize_t|ptrdiff_t|intptr_t|intmax_t"))
} else if (Token::Match(tok, "std| ::| ssize_t|ptrdiff_t|intptr_t|intmax_t")) {
if (isCPP11 && tok->strAt(-1) == "using" && tok->strAt(1) == "=")
continue;
isUnsigned = false;
else
} else
continue;
bool inStd = false;

View File

@ -349,6 +349,8 @@ private:
TEST_CASE(auto10); // #8020
TEST_CASE(unionWithConstructor);
TEST_CASE(using1);
}
void array() {
@ -5313,6 +5315,50 @@ private:
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 3);
}
void using1() {
Standards::cppstd_t original_std = settings1.standards.cpp;
settings1.standards.cpp = Standards::CPP11;
GET_SYMBOL_DB("using INT = int;\n\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);
}
}
};
REGISTER_TEST(TestSymbolDatabase)