diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index dda3e9b1e0b..5da07aa30b2 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -7017,6 +7017,10 @@ void SymbolDatabase::setValueType(Token* tok, const ValueType& valuetype, const setAutoTokenProperties(autoTok); if (vt2->pointer > vt.pointer) vt.pointer++; + if (Token::simpleMatch(autoTok->next(), "&")) + vt.reference = Reference::LValue; + if (Token::simpleMatch(autoTok->next(), "&&")) + vt.reference = Reference::RValue; setValueType(var1Tok, vt); if (var1Tok != parent->previous()) setValueType(parent->previous(), vt); @@ -7291,15 +7295,55 @@ void SymbolDatabase::setValueType(Token* tok, const ValueType& valuetype, const } // c++17 auto type deduction of braced init list - if (parent->isCpp() && mSettings.standards.cpp >= Standards::CPP17 && vt2 && Token::Match(parent->tokAt(-2), "auto %var% {")) { - Token *autoTok = parent->tokAt(-2); - setValueType(autoTok, *vt2); - setAutoTokenProperties(autoTok); - if (parent->previous()->variable()) - const_cast(parent->previous()->variable())->setValueType(*vt2); - else - debugMessage(parent->previous(), "debug", "Missing variable class for variable with varid"); - return; + if (parent->isCpp() && mSettings.standards.cpp >= Standards::CPP17 + && Token::Match(parent->astOperand1(), "%var% {") && vt2) { + + auto reference = Reference::None; + nonneg int pointer = 0; + nonneg int constness = 0; + nonneg int volatileness = 0; + + Token *varTok = parent->astOperand1(); + Token *typeTok = varTok->previous(); + + while (Token::Match(typeTok, "&|&&|*|const|volatile")) { + if (typeTok->str() == "&") + reference = Reference::LValue; + else if (typeTok->str() == "&&") + reference = Reference::RValue; + else if (typeTok->str() == "*") + pointer++; + else if (typeTok->str() == "const") + constness |= 1 << pointer; + else if (typeTok->str() == "volatile") + volatileness |= 1 << pointer; + typeTok = typeTok->previous(); + } + + if (typeTok->str() == "auto") { + setValueType(typeTok, *vt2); + setAutoTokenProperties(typeTok); + + auto *varVt = new ValueType(*vt2); + + varVt->reference = reference; + varVt->constness |= constness; + varVt->volatileness |= volatileness; + + if (Token::simpleMatch(typeTok->previous(), "const auto")) + varVt->constness |= 1 << pointer; + + if (Token::simpleMatch(typeTok->previous(), "volatile auto")) + varVt->volatileness |= 1 << pointer; + + varTok->setValueType(varVt); + + if (varTok->variable()) + const_cast(varTok->variable())->setValueType(*varVt); + else + debugMessage(varTok, "debug", "Missing variable class for variable with varid"); + return; + } } if (!vt1) diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp index e981c8ea546..9f603e8cac7 100644 --- a/test/testsymboldatabase.cpp +++ b/test/testsymboldatabase.cpp @@ -220,6 +220,8 @@ class TestSymbolDatabase : public TestFixture { TEST_CASE(VariableValueType4); // smart pointer type TEST_CASE(VariableValueType5); // smart pointer type TEST_CASE(VariableValueType6); // smart pointer type + TEST_CASE(VariableValueType7); + TEST_CASE(VariableValueType8); TEST_CASE(VariableValueTypeReferences); TEST_CASE(VariableValueTypeTemplate); @@ -1315,6 +1317,71 @@ class TestSymbolDatabase : public TestFixture { ASSERT(check->valueType()->smartPointerTypeToken); } + void VariableValueType7() { + GET_SYMBOL_DB("void f() {\n" + " auto x0 = 0;\n" + " auto &x1 = x0;\n" + " auto &x2 {x0};\n" + " auto &&x3 = 0;\n" + " auto &&x4 {0};\n" + "}\n"); + + const Token* x1 = Token::findsimplematch(tokenizer.tokens(), "x1"); + const Token* x2 = Token::findsimplematch(tokenizer.tokens(), "x2"); + const Token* x3 = Token::findsimplematch(tokenizer.tokens(), "x3"); + const Token* x4 = Token::findsimplematch(tokenizer.tokens(), "x4"); + + ASSERT(x1); + ASSERT(x2); + ASSERT(x3); + ASSERT(x4); + + ASSERT_EQUALS_ENUM(ValueType::INT, x1->valueType()->type); + ASSERT_EQUALS_ENUM(ValueType::INT, x2->valueType()->type); + ASSERT_EQUALS_ENUM(ValueType::INT, x3->valueType()->type); + ASSERT_EQUALS_ENUM(ValueType::INT, x4->valueType()->type); + + ASSERT_EQUALS_ENUM(Reference::LValue, x1->valueType()->reference); + ASSERT_EQUALS_ENUM(Reference::LValue, x2->valueType()->reference); + ASSERT_EQUALS_ENUM(Reference::RValue, x3->valueType()->reference); + ASSERT_EQUALS_ENUM(Reference::RValue, x4->valueType()->reference); + } + + void VariableValueType8() { + GET_SYMBOL_DB("void f() {\n" + " char buf[128];\n" + " const auto *const x0 {buf};\n" + " auto *const x1 {buf};\n" + " const auto *x2 {buf};\n" + " auto x3 {buf};\n" + "}\n"); + + const Token* x0 = Token::findsimplematch(tokenizer.tokens(), "x0"); + const Token* x1 = Token::findsimplematch(tokenizer.tokens(), "x1"); + const Token* x2 = Token::findsimplematch(tokenizer.tokens(), "x2"); + const Token* x3 = Token::findsimplematch(tokenizer.tokens(), "x3"); + + ASSERT(x0); + ASSERT(x1); + ASSERT(x2); + ASSERT(x3); + + ASSERT_EQUALS_ENUM(ValueType::CHAR, x0->valueType()->type); + ASSERT_EQUALS_ENUM(ValueType::CHAR, x1->valueType()->type); + ASSERT_EQUALS_ENUM(ValueType::CHAR, x2->valueType()->type); + ASSERT_EQUALS_ENUM(ValueType::CHAR, x3->valueType()->type); + + ASSERT_EQUALS(3, x0->valueType()->constness); + ASSERT_EQUALS(1, x1->valueType()->constness); + ASSERT_EQUALS(2, x2->valueType()->constness); + ASSERT_EQUALS(0, x3->valueType()->constness); + + ASSERT_EQUALS(1, x0->valueType()->pointer); + ASSERT_EQUALS(1, x1->valueType()->pointer); + ASSERT_EQUALS(1, x2->valueType()->pointer); + ASSERT_EQUALS(1, x3->valueType()->pointer); + } + void VariableValueTypeReferences() { { GET_SYMBOL_DB("void foo(int x) {}\n");