diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 943c57ffc..6a8d48241 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -2016,6 +2016,11 @@ void Variable::evaluate(const Settings* settings) 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; mValueType = new ValueType(valueType); 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%")) { - 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) @@ -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) return; if (parent->astOperand2() && !vt2) @@ -5800,7 +5817,17 @@ static const Token * parsedecl(const Token *type, ValueType * const valuetype, V break; 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; else if (type->isUnsigned()) valuetype->sign = ValueType::Sign::UNSIGNED; @@ -6215,6 +6242,8 @@ void SymbolDatabase::setValueTypeInTokenList(bool reportDebugWarnings, Token *to setValueType(tok, ValueType::parseDecl(functionScope->function->retDef, mSettings)); } else if (tok->variable()) { setValueType(tok, *tok->variable()); + if (!tok->variable()->valueType() && tok->valueType()) + const_cast(tok->variable())->setValueType(*tok->valueType()); } else if (tok->enumerator()) { setValueType(tok, *tok->enumerator()); } else if (tok->isKeyword() && tok->str() == "new") { diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 9d1ffdd61..481438682 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -3476,6 +3476,15 @@ void Tokenizer::setVarIdPass1() syntaxError(errTok); } 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) inlineFunction = true; diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp index 2c4bf4c1a..b2615d390 100644 --- a/test/testsymboldatabase.cpp +++ b/test/testsymboldatabase.cpp @@ -155,6 +155,7 @@ private: TEST_CASE(isVariablePointerToConstVolatilePointer); TEST_CASE(isVariableMultiplePointersAndQualifiers); TEST_CASE(variableVolatile); + TEST_CASE(isVariableDecltype); TEST_CASE(VariableValueType1); TEST_CASE(VariableValueType2); @@ -1290,6 +1291,33 @@ private: 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() { GET_SYMBOL_DB("struct Foo {\n" " int x;\n" diff --git a/test/testvarid.cpp b/test/testvarid.cpp index 35786f48d..58f30c33d 100644 --- a/test/testvarid.cpp +++ b/test/testvarid.cpp @@ -209,6 +209,7 @@ private: TEST_CASE(setVarIdStructMembers1); TEST_CASE(decltype1); + TEST_CASE(decltype2); TEST_CASE(exprid1); } @@ -3279,6 +3280,12 @@ private: 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() { const std::string actual = tokenizeExpr( "struct A {\n"