diff --git a/src/libs/3rdparty/cplusplus/Bind.cpp b/src/libs/3rdparty/cplusplus/Bind.cpp index 0bedfd04f41..25585083654 100644 --- a/src/libs/3rdparty/cplusplus/Bind.cpp +++ b/src/libs/3rdparty/cplusplus/Bind.cpp @@ -33,7 +33,7 @@ #include #include #include - +#include using namespace CPlusPlus; @@ -459,6 +459,58 @@ bool Bind::visit(EnumeratorAST *ast) return false; } +namespace { + +bool isInteger(const StringLiteral *stringLiteral) +{ + const int size = stringLiteral->size(); + const char *chars = stringLiteral->chars(); + for (int i = 0; i < size; ++i) { + if (!isdigit(chars[i])) + return false; + } + return true; +} + +bool stringLiteralToInt(const StringLiteral *stringLiteral, int *output) +{ + if (!output) + return false; + + if (!isInteger(stringLiteral)) { + *output = 0; + return false; + } + + std::stringstream ss(std::string(stringLiteral->chars(), stringLiteral->size())); + const bool ok = ss >> *output; + if (!ok) + *output = 0; + + return ok; +} + +void calculateConstantValue(const Symbol *symbol, EnumeratorDeclaration *e, Control *control) +{ + if (symbol) { + if (const Declaration *decl = symbol->asDeclaration()) { + if (const EnumeratorDeclaration *previousEnumDecl = decl->asEnumeratorDeclarator()) { + if (const StringLiteral *constantValue = previousEnumDecl->constantValue()) { + int constantValueAsInt = 0; + if (stringLiteralToInt(constantValue, &constantValueAsInt)) { + ++constantValueAsInt; + const std::string buffer = std::to_string(constantValueAsInt); + e->setConstantValue(control->stringLiteral(buffer.c_str(), + unsigned(buffer.size()))); + } + } + } + } + } +} + +} // anonymous namespace + void Bind::enumerator(EnumeratorAST *ast, Enum *symbol) { (void) symbol; @@ -477,6 +529,10 @@ void Bind::enumerator(EnumeratorAST *ast, Enum *symbol) if (ExpressionAST *expr = ast->expression) e->setConstantValue(asStringLiteral(expr->firstToken(), expr->lastToken())); + else if (!symbol->isEmpty()) + calculateConstantValue(*(symbol->lastMember()-1), e, control()); + else + e->setConstantValue(control()->stringLiteral("0", 1)); symbol->addMember(e); } diff --git a/src/plugins/cppeditor/cppelementevaluator.cpp b/src/plugins/cppeditor/cppelementevaluator.cpp index 7d0ce8f3f93..086e33b3350 100644 --- a/src/plugins/cppeditor/cppelementevaluator.cpp +++ b/src/plugins/cppeditor/cppelementevaluator.cpp @@ -456,7 +456,7 @@ CppEnumerator::CppEnumerator(CPlusPlus::EnumeratorDeclaration *declaration) Overview overview; - Symbol *enumSymbol = declaration->enclosingScope()->asEnum(); + Symbol *enumSymbol = declaration->enclosingScope(); const QString enumName = overview.prettyName(LookupContext::fullyQualifiedName(enumSymbol)); const QString enumeratorName = overview.prettyName(declaration->name()); QString enumeratorValue; diff --git a/tests/auto/cplusplus/semantic/tst_semantic.cpp b/tests/auto/cplusplus/semantic/tst_semantic.cpp index 46f5d4e4762..e43825da87c 100644 --- a/tests/auto/cplusplus/semantic/tst_semantic.cpp +++ b/tests/auto/cplusplus/semantic/tst_semantic.cpp @@ -184,6 +184,11 @@ private slots: void lambda_2(); void diagnostic_error(); + + void enum_constantValue1(); + void enum_constantValue2(); + void enum_constantValue3(); + void enum_constantValue4(); }; void tst_Semantic::function_declaration_1() @@ -783,5 +788,107 @@ void tst_Semantic::diagnostic_error() QCOMPARE(doc->globals->memberCount(), 1U); } +namespace { +void testEnumaratorDeclarator(Enum *e, int enumDeclIndex, const char *expectedConstantValue) +{ + Declaration *enumMemberDeclaration = e->memberAt(enumDeclIndex)->asDeclaration(); + QVERIFY(enumMemberDeclaration); + EnumeratorDeclaration *enumeratorDeclaration = enumMemberDeclaration->asEnumeratorDeclarator(); + QVERIFY(enumeratorDeclaration); + if (const StringLiteral *constantValue = enumeratorDeclaration->constantValue()) + QCOMPARE(constantValue->chars(), expectedConstantValue); + else + QVERIFY(!expectedConstantValue); +} +} // anonymous + +void tst_Semantic::enum_constantValue1() +{ + QSharedPointer doc = document("\n" + "enum {\n" + "E1,\n" + "E2,\n" + "E3\n" + "};\n" + ); + + QCOMPARE(doc->errorCount, 0U); + QCOMPARE(doc->globals->memberCount(), 1U); + Enum *e = doc->globals->memberAt(0)->asEnum(); + QVERIFY(e); + QCOMPARE(e->memberCount(), 3U); + + testEnumaratorDeclarator(e, 0, "0"); + testEnumaratorDeclarator(e, 1, "1"); + testEnumaratorDeclarator(e, 2, "2"); +} + +void tst_Semantic::enum_constantValue2() +{ + QSharedPointer doc = document("\n" + "enum {\n" + "E1=10,\n" + "E2,\n" + "E3\n" + "};\n" + ); + + QCOMPARE(doc->errorCount, 0U); + QCOMPARE(doc->globals->memberCount(), 1U); + Enum *e = doc->globals->memberAt(0)->asEnum(); + QVERIFY(e); + QCOMPARE(e->memberCount(), 3U); + + testEnumaratorDeclarator(e, 0, "10"); + testEnumaratorDeclarator(e, 1, "11"); + testEnumaratorDeclarator(e, 2, "12"); +} + +void tst_Semantic::enum_constantValue3() +{ + QSharedPointer doc = document("\n" + "enum {\n" + "E1,\n" + "E2=10,\n" + "E3\n" + "};\n" + ); + + QCOMPARE(doc->errorCount, 0U); + QCOMPARE(doc->globals->memberCount(), 1U); + Enum *e = doc->globals->memberAt(0)->asEnum(); + QVERIFY(e); + QCOMPARE(e->memberCount(), 3U); + + testEnumaratorDeclarator(e, 0, "0"); + testEnumaratorDeclarator(e, 1, "10"); + testEnumaratorDeclarator(e, 2, "11"); +} + +void tst_Semantic::enum_constantValue4() +{ + QSharedPointer doc = document("\n" + "enum {\n" + "E1,\n" + "E2=E1+10,\n" + "E3,\n" + "E4=10,\n" + "E5\n" + "};\n" + ); + + QCOMPARE(doc->errorCount, 0U); + QCOMPARE(doc->globals->memberCount(), 1U); + Enum *e = doc->globals->memberAt(0)->asEnum(); + QVERIFY(e); + QCOMPARE(e->memberCount(), 5U); + + testEnumaratorDeclarator(e, 0, "0"); + testEnumaratorDeclarator(e, 1, "E1+10"); + testEnumaratorDeclarator(e, 2, NULL); + testEnumaratorDeclarator(e, 3, "10"); + testEnumaratorDeclarator(e, 4, "11"); +} + QTEST_MAIN(tst_Semantic) #include "tst_semantic.moc"