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:
parent
58034dee86
commit
cefb2131c7
|
@ -276,6 +276,21 @@ void SymbolDatabase::createSymbolDatabaseFindAllScopes()
|
||||||
tok = tok->tokAt(2);
|
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
|
// unnamed struct and union
|
||||||
else if (Token::Match(tok, "struct|union {") &&
|
else if (Token::Match(tok, "struct|union {") &&
|
||||||
Token::Match(tok->next()->link(), "} *|&| %name% ;|[")) {
|
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
|
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;
|
return false;
|
||||||
|
|
||||||
const Token* localTypeTok = skipScopeIdentifiers(tok);
|
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;
|
valuetype->sign = ValueType::Sign::SIGNED;
|
||||||
else if (type->isUnsigned())
|
else if (type->isUnsigned())
|
||||||
valuetype->sign = ValueType::Sign::UNSIGNED;
|
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));
|
valuetype->constness |= (1 << (valuetype->pointer - pointer0));
|
||||||
else if (const Library::Container *container = settings->library.detectContainer(type)) {
|
else if (const Library::Container *container = settings->library.detectContainer(type)) {
|
||||||
valuetype->type = ValueType::Type::CONTAINER;
|
valuetype->type = ValueType::Type::CONTAINER;
|
||||||
|
|
|
@ -100,13 +100,24 @@ public:
|
||||||
std::vector<BaseInfo> derivedFrom;
|
std::vector<BaseInfo> derivedFrom;
|
||||||
std::list<FriendInfo> friendList;
|
std::list<FriendInfo> friendList;
|
||||||
|
|
||||||
|
const Token * typeStart;
|
||||||
|
const Token * typeEnd;
|
||||||
|
|
||||||
Type(const Token* classDef_ = nullptr, const Scope* classScope_ = nullptr, const Scope* enclosingScope_ = nullptr) :
|
Type(const Token* classDef_ = nullptr, const Scope* classScope_ = nullptr, const Scope* enclosingScope_ = nullptr) :
|
||||||
classDef(classDef_),
|
classDef(classDef_),
|
||||||
classScope(classScope_),
|
classScope(classScope_),
|
||||||
enclosingScope(enclosingScope_),
|
enclosingScope(enclosingScope_),
|
||||||
needInitialization(Unknown) {
|
needInitialization(Unknown),
|
||||||
|
typeStart(nullptr),
|
||||||
|
typeEnd(nullptr) {
|
||||||
if (classDef_ && classDef_->str() == "enum")
|
if (classDef_ && classDef_->str() == "enum")
|
||||||
needInitialization = True;
|
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;
|
const std::string& name() const;
|
||||||
|
@ -123,6 +134,10 @@ public:
|
||||||
return classDef && classDef->str() == "enum";
|
return classDef && classDef->str() == "enum";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isTypeAlias() const {
|
||||||
|
return classDef && classDef->str() == "using";
|
||||||
|
}
|
||||||
|
|
||||||
bool isStructType() const {
|
bool isStructType() const {
|
||||||
return classDef && classDef->str() == "struct";
|
return classDef && classDef->str() == "struct";
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
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..
|
// Split up variable declarations..
|
||||||
// "int a=4;" => "int a; a=4;"
|
// "int a=4;" => "int a; a=4;"
|
||||||
bool finishedwithkr = true;
|
bool finishedwithkr = true;
|
||||||
|
@ -5586,6 +5588,8 @@ void Tokenizer::simplifyVarDecl(Token * tokBegin, const Token * const tokEnd, co
|
||||||
continue;
|
continue;
|
||||||
if (Token::Match(type0, "else|return|public:|protected:|private:"))
|
if (Token::Match(type0, "else|return|public:|protected:|private:"))
|
||||||
continue;
|
continue;
|
||||||
|
if (isCPP11 && type0->str() == "using")
|
||||||
|
continue;
|
||||||
|
|
||||||
bool isconst = false;
|
bool isconst = false;
|
||||||
bool isstatic = false;
|
bool isstatic = false;
|
||||||
|
@ -5828,6 +5832,8 @@ void Tokenizer::simplifyVarDecl(Token * tokBegin, const Token * const tokEnd, co
|
||||||
|
|
||||||
void Tokenizer::simplifyPlatformTypes()
|
void Tokenizer::simplifyPlatformTypes()
|
||||||
{
|
{
|
||||||
|
const bool isCPP11 = _settings->standards.cpp >= Standards::CPP11;
|
||||||
|
|
||||||
enum { isLongLong, isLong, isInt } type;
|
enum { isLongLong, isLong, isInt } type;
|
||||||
|
|
||||||
/** @todo This assumes a flat address space. Not true for segmented address space (FAR *). */
|
/** @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%"))
|
if (!Token::Match(tok, "std| ::| %type%"))
|
||||||
continue;
|
continue;
|
||||||
bool isUnsigned;
|
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;
|
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;
|
isUnsigned = false;
|
||||||
else
|
} else
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
bool inStd = false;
|
bool inStd = false;
|
||||||
|
|
|
@ -349,6 +349,8 @@ private:
|
||||||
TEST_CASE(auto10); // #8020
|
TEST_CASE(auto10); // #8020
|
||||||
|
|
||||||
TEST_CASE(unionWithConstructor);
|
TEST_CASE(unionWithConstructor);
|
||||||
|
|
||||||
|
TEST_CASE(using1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void array() {
|
void array() {
|
||||||
|
@ -5313,6 +5315,50 @@ private:
|
||||||
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() {
|
||||||
|
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)
|
REGISTER_TEST(TestSymbolDatabase)
|
||||||
|
|
Loading…
Reference in New Issue