improved decltype() handling
This commit is contained in:
parent
a6a5cbe6c9
commit
6e8f77c519
|
@ -2016,6 +2016,11 @@ void Variable::evaluate(const Settings* settings)
|
||||||
|
|
||||||
void Variable::setValueType(const ValueType &valueType)
|
void Variable::setValueType(const ValueType &valueType)
|
||||||
{
|
{
|
||||||
|
if (valueType.type == ValueType::Type::UNKNOWN_TYPE) {
|
||||||
|
const Token *declType = Token::findsimplematch(mTypeStartToken, "decltype (", mTypeEndToken);
|
||||||
|
if (declType && !declType->next()->valueType())
|
||||||
|
return;
|
||||||
|
}
|
||||||
delete mValueType;
|
delete mValueType;
|
||||||
mValueType = new ValueType(valueType);
|
mValueType = new ValueType(valueType);
|
||||||
if ((mValueType->pointer > 0) && (!isArray() || Token::Match(mNameToken->previous(), "( * %name% )")))
|
if ((mValueType->pointer > 0) && (!isArray() || Token::Match(mNameToken->previous(), "( * %name% )")))
|
||||||
|
@ -4205,7 +4210,14 @@ bool Scope::isVariableDeclaration(const Token* const tok, const Token*& vartok,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (Token::Match(localTypeTok, "%type%")) {
|
} else if (Token::Match(localTypeTok, "%type%")) {
|
||||||
localVarTok = skipPointersAndQualifiers(localTypeTok->next());
|
|
||||||
|
if (isCPP11 && Token::simpleMatch(localTypeTok, "decltype (") && Token::Match(localTypeTok->linkAt(1), ") %name%|*|&|&&"))
|
||||||
|
localVarTok = skipPointersAndQualifiers(localTypeTok->linkAt(1)->next());
|
||||||
|
else {
|
||||||
|
localVarTok = skipPointersAndQualifiers(localTypeTok->next());
|
||||||
|
if (isCPP11 && Token::simpleMatch(localVarTok, "decltype (") && Token::Match(localVarTok->linkAt(1), ") %name%|*|&|&&"))
|
||||||
|
localVarTok = skipPointersAndQualifiers(localVarTok->linkAt(1)->next());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!localVarTok)
|
if (!localVarTok)
|
||||||
|
@ -5670,6 +5682,11 @@ void SymbolDatabase::setValueType(Token *tok, const ValueType &valuetype)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mIsCpp && vt2 && Token::simpleMatch(parent->previous(), "decltype (")) {
|
||||||
|
setValueType(parent, *vt2);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!vt1)
|
if (!vt1)
|
||||||
return;
|
return;
|
||||||
if (parent->astOperand2() && !vt2)
|
if (parent->astOperand2() && !vt2)
|
||||||
|
@ -5800,7 +5817,17 @@ static const Token * parsedecl(const Token *type, ValueType * const valuetype, V
|
||||||
break;
|
break;
|
||||||
par = true;
|
par = true;
|
||||||
}
|
}
|
||||||
if (type->isSigned())
|
if (Token::simpleMatch(type, "decltype (") && type->next()->valueType()) {
|
||||||
|
const ValueType *vt2 = type->next()->valueType();
|
||||||
|
if (valuetype->sign == ValueType::Sign::UNKNOWN_SIGN)
|
||||||
|
valuetype->sign = vt2->sign;
|
||||||
|
if (valuetype->type == ValueType::Type::UNKNOWN_TYPE)
|
||||||
|
valuetype->type = vt2->type;
|
||||||
|
valuetype->constness += vt2->constness;
|
||||||
|
valuetype->pointer += vt2->pointer;
|
||||||
|
type = type->linkAt(1)->next();
|
||||||
|
continue;
|
||||||
|
} else if (type->isSigned())
|
||||||
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;
|
||||||
|
@ -6215,6 +6242,8 @@ void SymbolDatabase::setValueTypeInTokenList(bool reportDebugWarnings, Token *to
|
||||||
setValueType(tok, ValueType::parseDecl(functionScope->function->retDef, mSettings));
|
setValueType(tok, ValueType::parseDecl(functionScope->function->retDef, mSettings));
|
||||||
} else if (tok->variable()) {
|
} else if (tok->variable()) {
|
||||||
setValueType(tok, *tok->variable());
|
setValueType(tok, *tok->variable());
|
||||||
|
if (!tok->variable()->valueType() && tok->valueType())
|
||||||
|
const_cast<Variable*>(tok->variable())->setValueType(*tok->valueType());
|
||||||
} else if (tok->enumerator()) {
|
} else if (tok->enumerator()) {
|
||||||
setValueType(tok, *tok->enumerator());
|
setValueType(tok, *tok->enumerator());
|
||||||
} else if (tok->isKeyword() && tok->str() == "new") {
|
} else if (tok->isKeyword() && tok->str() == "new") {
|
||||||
|
|
|
@ -3476,6 +3476,15 @@ void Tokenizer::setVarIdPass1()
|
||||||
syntaxError(errTok);
|
syntaxError(errTok);
|
||||||
}
|
}
|
||||||
if (decl) {
|
if (decl) {
|
||||||
|
if (isCPP()) {
|
||||||
|
if (Token *declTypeTok = Token::findsimplematch(tok, "decltype (", tok2)) {
|
||||||
|
for (Token *declTok = declTypeTok->linkAt(1); declTok != declTypeTok; declTok = declTok->previous()) {
|
||||||
|
if (declTok->isName() && !Token::Match(declTok->previous(), "::|.") && variableMap.hasVariable(declTok->str()))
|
||||||
|
declTok->varId(variableMap.find(declTok->str())->second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (tok->str() == "(" && isFunctionHead(tok,"{") && scopeStack.top().isExecutable)
|
if (tok->str() == "(" && isFunctionHead(tok,"{") && scopeStack.top().isExecutable)
|
||||||
inlineFunction = true;
|
inlineFunction = true;
|
||||||
|
|
||||||
|
|
|
@ -155,6 +155,7 @@ private:
|
||||||
TEST_CASE(isVariablePointerToConstVolatilePointer);
|
TEST_CASE(isVariablePointerToConstVolatilePointer);
|
||||||
TEST_CASE(isVariableMultiplePointersAndQualifiers);
|
TEST_CASE(isVariableMultiplePointersAndQualifiers);
|
||||||
TEST_CASE(variableVolatile);
|
TEST_CASE(variableVolatile);
|
||||||
|
TEST_CASE(isVariableDecltype);
|
||||||
|
|
||||||
TEST_CASE(VariableValueType1);
|
TEST_CASE(VariableValueType1);
|
||||||
TEST_CASE(VariableValueType2);
|
TEST_CASE(VariableValueType2);
|
||||||
|
@ -1290,6 +1291,33 @@ private:
|
||||||
ASSERT(y->variable()->isVolatile());
|
ASSERT(y->variable()->isVolatile());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void isVariableDecltype() {
|
||||||
|
GET_SYMBOL_DB("int x;\n"
|
||||||
|
"decltype(x) a;\n"
|
||||||
|
"const decltype(x) b;\n"
|
||||||
|
"decltype(x) *c;\n");
|
||||||
|
ASSERT(db);
|
||||||
|
ASSERT_EQUALS(4, db->scopeList.front().varlist.size());
|
||||||
|
|
||||||
|
const Variable *a = Token::findsimplematch(tokenizer.tokens(), "a")->variable();
|
||||||
|
ASSERT(a);
|
||||||
|
ASSERT_EQUALS("a", a->name());
|
||||||
|
ASSERT(a->valueType());
|
||||||
|
ASSERT_EQUALS("signed int", a->valueType()->str());
|
||||||
|
|
||||||
|
const Variable *b = Token::findsimplematch(tokenizer.tokens(), "b")->variable();
|
||||||
|
ASSERT(b);
|
||||||
|
ASSERT_EQUALS("b", b->name());
|
||||||
|
ASSERT(b->valueType());
|
||||||
|
ASSERT_EQUALS("const signed int", b->valueType()->str());
|
||||||
|
|
||||||
|
const Variable *c = Token::findsimplematch(tokenizer.tokens(), "c")->variable();
|
||||||
|
ASSERT(c);
|
||||||
|
ASSERT_EQUALS("c", c->name());
|
||||||
|
ASSERT(c->valueType());
|
||||||
|
ASSERT_EQUALS("signed int *", c->valueType()->str());
|
||||||
|
}
|
||||||
|
|
||||||
void arrayMemberVar1() {
|
void arrayMemberVar1() {
|
||||||
GET_SYMBOL_DB("struct Foo {\n"
|
GET_SYMBOL_DB("struct Foo {\n"
|
||||||
" int x;\n"
|
" int x;\n"
|
||||||
|
|
|
@ -209,6 +209,7 @@ private:
|
||||||
TEST_CASE(setVarIdStructMembers1);
|
TEST_CASE(setVarIdStructMembers1);
|
||||||
|
|
||||||
TEST_CASE(decltype1);
|
TEST_CASE(decltype1);
|
||||||
|
TEST_CASE(decltype2);
|
||||||
|
|
||||||
TEST_CASE(exprid1);
|
TEST_CASE(exprid1);
|
||||||
}
|
}
|
||||||
|
@ -3279,6 +3280,12 @@ private:
|
||||||
ASSERT_EQUALS(expected, tokenize(code));
|
ASSERT_EQUALS(expected, tokenize(code));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void decltype2() {
|
||||||
|
const char code[] = "int x; decltype(x) y;";
|
||||||
|
const char expected[] = "1: int x@1 ; decltype ( x@1 ) y@2 ;\n";
|
||||||
|
ASSERT_EQUALS(expected, tokenize(code));
|
||||||
|
}
|
||||||
|
|
||||||
void exprid1() {
|
void exprid1() {
|
||||||
const std::string actual = tokenizeExpr(
|
const std::string actual = tokenizeExpr(
|
||||||
"struct A {\n"
|
"struct A {\n"
|
||||||
|
|
Loading…
Reference in New Issue