/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ****************************************************************************/ #include #include #include #include #include #include #include //TESTED_COMPONENT=src/libs/cplusplus using namespace CPlusPlus; class tst_AST: public QObject { Q_OBJECT Control control; public: TranslationUnit *parse(const QByteArray &source, TranslationUnit::ParseMode mode, bool blockErrors = false, bool qtMocRun = false, bool cxx11Enabled = false) { const StringLiteral *fileId = control.stringLiteral(""); LanguageFeatures features; features.cxx11Enabled = cxx11Enabled; features.cxxEnabled = true; features.objCEnabled = true; features.qtEnabled = qtMocRun; features.qtKeywordsEnabled = qtMocRun; features.qtMocRunEnabled = qtMocRun; TranslationUnit *unit = new TranslationUnit(&control, fileId); unit->setLanguageFeatures(features); unit->setSource(source.constData(), source.length()); unit->blockErrors(blockErrors); unit->parse(mode); // Sanity check: Visit all AST nodes if (AST *ast = unit->ast()) { ASTVisitor visitor(unit); visitor.accept(ast); } return unit; } TranslationUnit *parseDeclaration(const QByteArray &source, bool blockErrors = false, bool qtMocRun = false, bool cxx11Enabled = false) { return parse(source, TranslationUnit::ParseDeclaration, blockErrors, qtMocRun, cxx11Enabled); } TranslationUnit *parseExpression(const QByteArray &source) { return parse(source, TranslationUnit::ParseExpression); } TranslationUnit *parseStatement(const QByteArray &source, bool cxx11Enabled = false) { return parse(source, TranslationUnit::ParseStatement, false, false, cxx11Enabled); } class Diagnostic: public DiagnosticClient { public: int errorCount; Diagnostic() : errorCount(0) { } virtual void report(int /*level*/, const StringLiteral *fileName, unsigned line, unsigned column, const char *format, va_list ap) { ++errorCount; qDebug() << fileName->chars()<<':'< class T : Args... {};" void cpp11_variadic_inheritance(); // Q_PROPERTY void cpp_qproperty(); void cpp_qproperty_data(); // objc++ void objc_simple_class(); void objc_attributes_followed_by_at_keyword(); void objc_protocol_forward_declaration_1(); void objc_protocol_definition_1(); void objc_method_attributes_1(); void objc_selector_error_recovery_1(); void objc_selector_error_recovery_2(); void objc_try_statement_1(); void objc_try_statement_2(); void objc_try_statement_3(); void objc_throw_statement(); // expressions with (square) brackets void normal_array_access(); void array_access_with_nested_expression(); void objc_msg_send_expression(); void objc_msg_send_expression_without_selector(); // Qt "keywords" void q_enum_1(); void declarationWithNewStatement(); void declarationWithNewStatement_data(); void incomplete_ast(); void unnamed_class(); void unnamed_class_data(); void expensiveExpression(); void invalidCode_data(); void invalidCode(); void enumDeclaration(); void invalidEnumClassDeclaration(); }; void tst_AST::gcc_attributes_1() { QSharedPointer unit(parseDeclaration("\n" "static inline void *__attribute__((__always_inline__)) _mm_malloc(size_t size, size_t align);" )); } void tst_AST::gcc_attributes_2() { QSharedPointer unit(parseDeclaration( "\nnamespace std __attribute__ ((__visibility__ (\"default\"))) {\n}\n" )); AST *ast = unit->ast(); QVERIFY(ast); NamespaceAST* ns = ast->asNamespace(); QVERIFY(ns); QCOMPARE(unit->spell(ns->identifier_token), "std"); QVERIFY(ns->attribute_list); QVERIFY(!ns->attribute_list->next); QVERIFY(ns->attribute_list->value); GnuAttributeSpecifierAST *attrSpec = ns->attribute_list->value->asGnuAttributeSpecifier(); QVERIFY(attrSpec); QVERIFY(attrSpec->attribute_list); QVERIFY(!attrSpec->attribute_list->next); QVERIFY(attrSpec->attribute_list->value); GnuAttributeAST *attr = attrSpec->attribute_list->value->asGnuAttribute(); QVERIFY(attr); QCOMPARE(unit->spell(attr->identifier_token), "__visibility__"); QVERIFY(attr->expression_list); QVERIFY(!attr->expression_list->next); QVERIFY(attr->expression_list->value); StringLiteralAST *e = attr->expression_list->value->asStringLiteral(); QVERIFY(e); QVERIFY(!e->next); QCOMPARE(unit->spell(e->literal_token), "default"); } void tst_AST::gcc_attributes_3() { const char *inp = "\nnamespace std X {\n}\n"; QSharedPointer unit(parseDeclaration(inp)); AST *ast = unit->ast(); QVERIFY(ast); NamespaceAST* ns = ast->asNamespace(); QVERIFY(ns); QCOMPARE(unit->spell(ns->identifier_token), "std"); QVERIFY(!ns->attribute_list); QVERIFY(ns->linkage_body); LinkageBodyAST *link = ns->linkage_body->asLinkageBody(); QVERIFY(link); QCOMPARE(unit->tokenKind(link->lbrace_token), T_LBRACE); QVERIFY(!link->declaration_list); QCOMPARE(unit->tokenKind(link->rbrace_token), T_RBRACE); } void tst_AST::crash_test_1() { QSharedPointer unit(parseStatement("decltype auto\n")); AST *ast = unit->ast(); QVERIFY(ast); } void tst_AST::thread_local_1() { QSharedPointer unit(parseStatement("__thread int i;\n")); AST *ast = unit->ast(); QVERIFY(ast); QCOMPARE(diag.errorCount, 0); QCOMPARE(Token::name(T_THREAD_LOCAL), "thread_local"); QCOMPARE(Token::name(T___THREAD), "__thread"); } void tst_AST::simple_declaration_1() { QSharedPointer unit(parseStatement("\n" "a * b = 10;" )); AST *ast = unit->ast(); QVERIFY(ast); DeclarationStatementAST *declStmt = ast->asDeclarationStatement(); QVERIFY(declStmt); } void tst_AST::simple_name_1() { QSharedPointer unit(parseExpression("a")); AST *ast = unit->ast(); QVERIFY(ast != 0); QVERIFY(ast->asIdExpression()->name->asSimpleName() != 0); QCOMPARE(ast->asIdExpression()->name->asSimpleName()->identifier_token, 1U); } void tst_AST::template_id_1() { QSharedPointer unit(parseExpression("list<10>")); AST *ast = unit->ast(); QVERIFY(ast != 0); QVERIFY(ast->asIdExpression()->name->asTemplateId() != 0); QCOMPARE(ast->asIdExpression()->name->asTemplateId()->identifier_token, 1U); QCOMPARE(ast->asIdExpression()->name->asTemplateId()->less_token, 2U); QVERIFY(ast->asIdExpression()->name->asTemplateId()->template_argument_list != 0); QVERIFY(ast->asIdExpression()->name->asTemplateId()->template_argument_list->value != 0); QVERIFY(ast->asIdExpression()->name->asTemplateId()->template_argument_list->value->asNumericLiteral() != 0); QCOMPARE(ast->asIdExpression()->name->asTemplateId()->template_argument_list->value->asNumericLiteral()->literal_token, 3U); QVERIFY(ast->asIdExpression()->name->asTemplateId()->template_argument_list->next == 0); QCOMPARE(ast->asIdExpression()->name->asTemplateId()->greater_token, 4U); } void tst_AST::new_expression_1() { QSharedPointer unit(parseExpression("\n" "new char" )); AST *ast = unit->ast(); QVERIFY(ast != 0); NewExpressionAST *expr = ast->asNewExpression(); QVERIFY(expr != 0); QCOMPARE(expr->scope_token, 0U); QCOMPARE(expr->new_token, 1U); QVERIFY(expr->new_placement == 0); QCOMPARE(expr->lparen_token, 0U); QVERIFY(expr->type_id == 0); QCOMPARE(expr->rparen_token, 0U); QVERIFY(expr->new_type_id != 0); QVERIFY(expr->new_initializer == 0); QVERIFY(expr->new_type_id->type_specifier_list != 0); QVERIFY(expr->new_type_id->ptr_operator_list == 0); QVERIFY(expr->new_type_id->new_array_declarator_list == 0); } void tst_AST::new_expression_2() { QSharedPointer unit(parseStatement("\n" "::new(__p) _Tp(__val);" )); AST *ast = unit->ast(); QVERIFY(ast != 0); ExpressionStatementAST *stmt = ast->asExpressionStatement(); QVERIFY(stmt != 0); QVERIFY(stmt->expression != 0); QVERIFY(stmt->semicolon_token != 0); NewExpressionAST *expr = stmt->expression->asNewExpression(); QVERIFY(expr != 0); QCOMPARE(expr->scope_token, 1U); QCOMPARE(expr->new_token, 2U); QVERIFY(expr->new_placement != 0); QCOMPARE(expr->lparen_token, 0U); QVERIFY(expr->type_id == 0); QCOMPARE(expr->rparen_token, 0U); QVERIFY(expr->new_type_id != 0); QVERIFY(expr->new_initializer != 0); } void tst_AST::condition_1() { QSharedPointer unit(parseExpression("\n" "(x < 0 && y > (int) a)" )); AST *ast = unit->ast(); QVERIFY(ast != 0); NestedExpressionAST *nestedExpr = ast->asNestedExpression(); QVERIFY(nestedExpr); QVERIFY(nestedExpr->expression); BinaryExpressionAST *andExpr = nestedExpr->expression->asBinaryExpression(); QVERIFY(andExpr); QCOMPARE(unit->tokenKind(andExpr->binary_op_token), T_AMPER_AMPER); QVERIFY(andExpr->left_expression); QVERIFY(andExpr->right_expression); BinaryExpressionAST *ltExpr = andExpr->left_expression->asBinaryExpression(); QVERIFY(ltExpr); QCOMPARE(unit->tokenKind(ltExpr->binary_op_token), T_LESS); QVERIFY(ltExpr->left_expression); QVERIFY(ltExpr->right_expression); SimpleNameAST *x = ltExpr->left_expression->asIdExpression()->name->asSimpleName(); QVERIFY(x); QCOMPARE(unit->spell(x->identifier_token), "x"); NumericLiteralAST *zero = ltExpr->right_expression->asNumericLiteral(); QVERIFY(zero); QCOMPARE(unit->spell(zero->literal_token), "0"); BinaryExpressionAST *gtExpr = andExpr->right_expression->asBinaryExpression(); QVERIFY(gtExpr); QCOMPARE(unit->tokenKind(gtExpr->binary_op_token), T_GREATER); QVERIFY(gtExpr->left_expression); QVERIFY(gtExpr->right_expression); SimpleNameAST *y = gtExpr->left_expression->asIdExpression()->name->asSimpleName(); QVERIFY(y); QCOMPARE(unit->spell(y->identifier_token), "y"); CastExpressionAST *cast = gtExpr->right_expression->asCastExpression(); QVERIFY(cast); QVERIFY(cast->type_id); QVERIFY(cast->expression); TypeIdAST *intType = cast->type_id->asTypeId(); QVERIFY(intType); // ### here we could check if the type is an actual int SimpleNameAST *a = cast->expression->asIdExpression()->name->asSimpleName(); QVERIFY(a); QCOMPARE(unit->spell(a->identifier_token), "a"); } void tst_AST::init_1() { QSharedPointer unit(parseDeclaration("\n" "x y[] = { X<10>, y };" )); AST *ast = unit->ast(); QVERIFY(ast != 0); } void tst_AST::conditional_1() { QSharedPointer unit(parseExpression("\n" "(x < 0 && y > (int) a) ? x == 1 : y = 1" )); AST *ast = unit->ast(); QVERIFY(ast != 0); ConditionalExpressionAST *conditional = ast->asConditionalExpression(); QVERIFY(conditional); QVERIFY(conditional->condition); QVERIFY(conditional->left_expression); QVERIFY(conditional->right_expression); NestedExpressionAST *nestedExpr = conditional->condition->asNestedExpression(); QVERIFY(nestedExpr); QVERIFY(nestedExpr->expression); BinaryExpressionAST *andExpr = nestedExpr->expression->asBinaryExpression(); QVERIFY(andExpr); QCOMPARE(unit->tokenKind(andExpr->binary_op_token), T_AMPER_AMPER); QVERIFY(andExpr->left_expression); QVERIFY(andExpr->right_expression); BinaryExpressionAST *ltExpr = andExpr->left_expression->asBinaryExpression(); QVERIFY(ltExpr); QCOMPARE(unit->tokenKind(ltExpr->binary_op_token), T_LESS); QVERIFY(ltExpr->left_expression); QVERIFY(ltExpr->right_expression); SimpleNameAST *x = ltExpr->left_expression->asIdExpression()->name->asSimpleName(); QVERIFY(x); QCOMPARE(unit->spell(x->identifier_token), "x"); NumericLiteralAST *zero = ltExpr->right_expression->asNumericLiteral(); QVERIFY(zero); QCOMPARE(unit->spell(zero->literal_token), "0"); BinaryExpressionAST *gtExpr = andExpr->right_expression->asBinaryExpression(); QVERIFY(gtExpr); QCOMPARE(unit->tokenKind(gtExpr->binary_op_token), T_GREATER); QVERIFY(gtExpr->left_expression); QVERIFY(gtExpr->right_expression); SimpleNameAST *y = gtExpr->left_expression->asIdExpression()->name->asSimpleName(); QVERIFY(y); QCOMPARE(unit->spell(y->identifier_token), "y"); CastExpressionAST *cast = gtExpr->right_expression->asCastExpression(); QVERIFY(cast); QVERIFY(cast->type_id); QVERIFY(cast->expression); TypeIdAST *intType = cast->type_id->asTypeId(); QVERIFY(intType); QVERIFY(! (intType->declarator)); QVERIFY(intType->type_specifier_list); QVERIFY(! (intType->type_specifier_list->next)); QVERIFY(intType->type_specifier_list->value); SimpleSpecifierAST *intSpec = intType->type_specifier_list->value->asSimpleSpecifier(); QVERIFY(intSpec); QCOMPARE(unit->spell(intSpec->specifier_token), "int"); SimpleNameAST *a = cast->expression->asIdExpression()->name->asSimpleName(); QVERIFY(a); QCOMPARE(unit->spell(a->identifier_token), "a"); BinaryExpressionAST *equals = conditional->left_expression->asBinaryExpression(); QVERIFY(equals); QCOMPARE(unit->tokenKind(equals->binary_op_token), T_EQUAL_EQUAL); x = equals->left_expression->asIdExpression()->name->asSimpleName(); QVERIFY(x); QCOMPARE(unit->spell(x->identifier_token), "x"); NumericLiteralAST *one = equals->right_expression->asNumericLiteral(); QVERIFY(one); QCOMPARE(unit->spell(one->literal_token), "1"); BinaryExpressionAST *assignment = conditional->right_expression->asBinaryExpression(); QVERIFY(assignment); QCOMPARE(unit->tokenKind(assignment->binary_op_token), T_EQUAL); y = assignment->left_expression->asIdExpression()->name->asSimpleName(); QVERIFY(y); QCOMPARE(unit->spell(y->identifier_token), "y"); one = assignment->right_expression->asNumericLiteral(); QVERIFY(one); QCOMPARE(unit->spell(one->literal_token), "1"); } void tst_AST::throw_1() { QSharedPointer unit(parseStatement("throw 1;")); AST *ast = unit->ast(); QVERIFY(ast != 0); QVERIFY(ast->asExpressionStatement()); } void tst_AST::templated_dtor_1() { QSharedPointer unit(parseStatement( "\n" "a.b::~b();" )); AST *ast = unit->ast(); QVERIFY(ast != 0); ExpressionStatementAST *e = ast->asExpressionStatement(); QVERIFY(e); QVERIFY(e->expression); CallAST *call = e->expression->asCall(); QVERIFY(call); QVERIFY(!call->expression_list); QVERIFY(call->base_expression); MemberAccessAST *mem = call->base_expression->asMemberAccess(); QVERIFY(mem); QCOMPARE(unit->spell(mem->base_expression->asIdExpression()->name->asSimpleName()->identifier_token), "a"); QualifiedNameAST *qName = mem->member_name->asQualifiedName(); QVERIFY(qName); QVERIFY(qName->nested_name_specifier_list); QVERIFY(!qName->nested_name_specifier_list->next); QVERIFY(qName->nested_name_specifier_list->value); QVERIFY(qName->nested_name_specifier_list->value->class_or_namespace_name); SimpleNameAST *bName = qName->nested_name_specifier_list->value->class_or_namespace_name->asSimpleName(); QVERIFY(bName); QCOMPARE(unit->spell(bName->identifier_token), "b"); QVERIFY(qName->unqualified_name); DestructorNameAST *dtor = qName->unqualified_name->asDestructorName(); QVERIFY(dtor); QVERIFY(dtor->unqualified_name); TemplateIdAST *tid = dtor->unqualified_name->asTemplateId(); QVERIFY(tid); QCOMPARE(unit->spell(tid->identifier_token), "b"); QVERIFY(tid->template_argument_list); QVERIFY(!tid->template_argument_list->next); QVERIFY(tid->template_argument_list->value); TypeIdAST *typeId = tid->template_argument_list->value->asTypeId(); QVERIFY(typeId); QVERIFY(!typeId->declarator); QVERIFY(typeId->type_specifier_list); QVERIFY(!typeId->type_specifier_list->next); QVERIFY(typeId->type_specifier_list->value); NamedTypeSpecifierAST *nts = typeId->type_specifier_list->value->asNamedTypeSpecifier(); QVERIFY(nts); QVERIFY(nts->name); SimpleNameAST *cName = nts->name->asSimpleName(); QVERIFY(cName); QCOMPARE(unit->spell(cName->identifier_token), "c"); } void tst_AST::templated_dtor_2() { QSharedPointer unit(parseStatement( "\n" "a.~b();" )); AST *ast = unit->ast(); QVERIFY(ast != 0); ExpressionStatementAST *e = ast->asExpressionStatement(); QVERIFY(e); QVERIFY(e->expression); CallAST *call = e->expression->asCall(); QVERIFY(call); QVERIFY(!call->expression_list); QVERIFY(call->base_expression); MemberAccessAST *mem = call->base_expression->asMemberAccess(); QVERIFY(mem); QCOMPARE(unit->spell(mem->base_expression->asIdExpression()->name->asSimpleName()->identifier_token), "a"); QVERIFY(mem->member_name); DestructorNameAST *dtor = mem->member_name->asDestructorName(); QVERIFY(dtor); QVERIFY(dtor->unqualified_name); TemplateIdAST *tid = dtor->unqualified_name->asTemplateId(); QVERIFY(tid); QCOMPARE(unit->spell(tid->identifier_token), "b"); QVERIFY(tid->template_argument_list); QVERIFY(!tid->template_argument_list->next); QVERIFY(tid->template_argument_list->value); TypeIdAST *typeId = tid->template_argument_list->value->asTypeId(); QVERIFY(typeId); QVERIFY(!typeId->declarator); QVERIFY(typeId->type_specifier_list); QVERIFY(!typeId->type_specifier_list->next); QVERIFY(typeId->type_specifier_list->value); NamedTypeSpecifierAST *nts = typeId->type_specifier_list->value->asNamedTypeSpecifier(); QVERIFY(nts); QVERIFY(nts->name); SimpleNameAST *cName = nts->name->asSimpleName(); QVERIFY(cName); QCOMPARE(unit->spell(cName->identifier_token), "c"); } void tst_AST::templated_dtor_3() { QSharedPointer unit(parseStatement( "\n" "a::~b();" )); AST *ast = unit->ast(); QVERIFY(ast != 0); ExpressionStatementAST *e = ast->asExpressionStatement(); QVERIFY(e); QVERIFY(e->expression); CallAST *call = e->expression->asCall(); QVERIFY(call); QVERIFY(!call->expression_list); QVERIFY(call->base_expression); IdExpressionAST *idExpr = call->base_expression->asIdExpression(); QVERIFY(idExpr); QVERIFY(idExpr->name); QualifiedNameAST *qName = idExpr->name->asQualifiedName(); QVERIFY(qName); QVERIFY(qName->nested_name_specifier_list); QVERIFY(!qName->nested_name_specifier_list->next); QVERIFY(qName->nested_name_specifier_list->value); QVERIFY(qName->nested_name_specifier_list->value->class_or_namespace_name); SimpleNameAST *bName = qName->nested_name_specifier_list->value->class_or_namespace_name->asSimpleName(); QVERIFY(bName); QCOMPARE(unit->spell(bName->identifier_token), "a"); QVERIFY(qName->unqualified_name); DestructorNameAST *dtor = qName->unqualified_name->asDestructorName(); QVERIFY(dtor); QVERIFY(dtor->unqualified_name); TemplateIdAST *tid = dtor->unqualified_name->asTemplateId(); QVERIFY(tid); QCOMPARE(unit->spell(tid->identifier_token), "b"); QVERIFY(tid->template_argument_list); QVERIFY(!tid->template_argument_list->next); QVERIFY(tid->template_argument_list->value); TypeIdAST *typeId = tid->template_argument_list->value->asTypeId(); QVERIFY(typeId); QVERIFY(!typeId->declarator); QVERIFY(typeId->type_specifier_list); QVERIFY(!typeId->type_specifier_list->next); QVERIFY(typeId->type_specifier_list->value); NamedTypeSpecifierAST *nts = typeId->type_specifier_list->value->asNamedTypeSpecifier(); QVERIFY(nts); QVERIFY(nts->name); SimpleNameAST *cName = nts->name->asSimpleName(); QVERIFY(cName); QCOMPARE(unit->spell(cName->identifier_token), "c"); } void tst_AST::templated_dtor_4() { QSharedPointer unit(parseStatement( "\n" "~b();" )); AST *ast = unit->ast(); QVERIFY(ast != 0); ExpressionStatementAST *e = ast->asExpressionStatement(); QVERIFY(e); QVERIFY(e->expression); UnaryExpressionAST *u = e->expression->asUnaryExpression(); QVERIFY(u); QCOMPARE(unit->tokenKind(u->unary_op_token), T_TILDE); QVERIFY(u->expression); CallAST *call = u->expression->asCall(); QVERIFY(call); QVERIFY(call->base_expression); IdExpressionAST *idExpr = call->base_expression->asIdExpression(); QVERIFY(idExpr); QVERIFY(idExpr->name); TemplateIdAST *tid = idExpr->name->asTemplateId(); QVERIFY(tid); QCOMPARE(unit->spell(tid->identifier_token), "b"); QVERIFY(tid->template_argument_list); QVERIFY(!tid->template_argument_list->next); QVERIFY(tid->template_argument_list->value); TypeIdAST *typeId = tid->template_argument_list->value->asTypeId(); QVERIFY(typeId); QVERIFY(!typeId->declarator); QVERIFY(typeId->type_specifier_list); QVERIFY(!typeId->type_specifier_list->next); QVERIFY(typeId->type_specifier_list->value); NamedTypeSpecifierAST *nts = typeId->type_specifier_list->value->asNamedTypeSpecifier(); QVERIFY(nts); QVERIFY(nts->name); SimpleNameAST *cName = nts->name->asSimpleName(); QVERIFY(cName); QCOMPARE(unit->spell(cName->identifier_token), "c"); } void tst_AST::templated_dtor_5() { QSharedPointer unit(parseExpression( "\n" "~a < b()" )); AST *ast = unit->ast(); QVERIFY(ast != 0); BinaryExpressionAST *binExpr = ast->asBinaryExpression(); QVERIFY(binExpr); QVERIFY(binExpr->left_expression); UnaryExpressionAST *notExpr = binExpr->left_expression->asUnaryExpression(); QVERIFY(notExpr); QCOMPARE(unit->tokenKind(notExpr->unary_op_token), T_TILDE); CallAST *call = binExpr->right_expression->asCall(); QVERIFY(call->base_expression); QVERIFY(!call->expression_list); IdExpressionAST *bExpr = call->base_expression->asIdExpression(); QVERIFY(bExpr); SimpleNameAST *bName = bExpr->name->asSimpleName(); QVERIFY(bName); QCOMPARE(unit->spell(bName->identifier_token), "b"); } void tst_AST::call_call_1() { QSharedPointer unit(parseStatement("method()->call();")); AST *ast = unit->ast(); QVERIFY(ast != 0); ExpressionStatementAST *exprStmt = ast->asExpressionStatement(); QVERIFY(exprStmt); ExpressionAST *expr = exprStmt->expression; QVERIFY(expr); CallAST *memberCall = expr->asCall(); QVERIFY(memberCall); QVERIFY(memberCall->base_expression); QVERIFY(!memberCall->expression_list); MemberAccessAST *member_xs = memberCall->base_expression->asMemberAccess(); QVERIFY(member_xs); QVERIFY(member_xs->member_name); SimpleNameAST *member_name = member_xs->member_name->asSimpleName(); QVERIFY(member_name); QVERIFY(member_name->identifier_token); QCOMPARE(unit->spell(member_name->identifier_token), "call"); QCOMPARE(unit->tokenKind(member_xs->access_token), T_ARROW); QVERIFY(member_xs->base_expression); CallAST *method_call = member_xs->base_expression->asCall(); QVERIFY(method_call); QVERIFY(!method_call->expression_list); QVERIFY(method_call->base_expression); IdExpressionAST *member_expr = method_call->base_expression->asIdExpression(); QVERIFY(member_expr); QVERIFY(member_expr->name); SimpleNameAST *member_name2 = member_expr->name->asSimpleName(); QVERIFY(member_name2); QVERIFY(member_name2->identifier_token); QCOMPARE(unit->spell(member_name2->identifier_token), "method"); } void tst_AST::function_call_1() { QSharedPointer unit(parseStatement("retranslateUi(blah);")); AST *ast = unit->ast(); QVERIFY(ast != 0); QVERIFY(ast->asExpressionStatement()); } void tst_AST::function_call_2() { QSharedPointer unit(parseStatement("retranslateUi(10);")); AST *ast = unit->ast(); QVERIFY(ast != 0); QVERIFY(ast->asExpressionStatement()); } void tst_AST::function_call_3() { QSharedPointer unit(parseStatement("advance();")); AST *ast = unit->ast(); QVERIFY(ast != 0); QVERIFY(ast->asExpressionStatement()); } void tst_AST::function_call_4() { QSharedPointer unit(parseStatement("checkPropertyAttribute(attrAst, propAttrs, ReadWrite);")); AST *ast = unit->ast(); QVERIFY(ast != 0); QVERIFY(ast->asExpressionStatement()); } void tst_AST::nested_deref_expression() { QSharedPointer unit(parseStatement("(*blah);")); AST *ast = unit->ast(); QVERIFY(ast != 0); QVERIFY(ast->asExpressionStatement()); } void tst_AST::assignment_1() { QSharedPointer unit(parseStatement("a(x) = 3;")); AST *ast = unit->ast(); QVERIFY(ast != 0); QVERIFY(ast->asExpressionStatement()); } void tst_AST::assignment_2() { QSharedPointer unit(parseStatement("(*blah) = 10;")); AST *ast = unit->ast(); QVERIFY(ast != 0); QVERIFY(ast->asExpressionStatement()); } void tst_AST::if_statement_1() { QSharedPointer unit(parseStatement("if (a) b;")); AST *ast = unit->ast(); QVERIFY(ast != 0); IfStatementAST *stmt = ast->asIfStatement(); QVERIFY(stmt != 0); QCOMPARE(stmt->if_token, 1U); QCOMPARE(stmt->lparen_token, 2U); QVERIFY(stmt->condition != 0); QCOMPARE(stmt->rparen_token, 4U); QVERIFY(stmt->statement != 0); QCOMPARE(stmt->else_token, 0U); QVERIFY(stmt->else_statement == 0); // check the `then' statement1 ExpressionStatementAST *then_stmt = stmt->statement->asExpressionStatement(); QVERIFY(then_stmt != 0); QVERIFY(then_stmt->expression != 0); QCOMPARE(then_stmt->semicolon_token, 6U); SimpleNameAST *id_expr = then_stmt->expression->asIdExpression()->name->asSimpleName(); QVERIFY(id_expr != 0); QCOMPARE(id_expr->identifier_token, 5U); } void tst_AST::if_statement_2() { QSharedPointer unit(parseStatement("if (x<0 && y>a);")); AST *ast = unit->ast(); QVERIFY(ast != 0); IfStatementAST *stmt = ast->asIfStatement(); QVERIFY(stmt != 0); QVERIFY(stmt->condition); QVERIFY(stmt->condition->asBinaryExpression()); QCOMPARE(unit->tokenKind(stmt->condition->asBinaryExpression()->binary_op_token), T_AMPER_AMPER); } void tst_AST::if_statement_3() { QSharedPointer unit(parseStatement("if (x<0 && x<0 && x<0 && x<0 && x<0 && x<0 && x<0);")); AST *ast = unit->ast(); QVERIFY(ast != 0); IfStatementAST *stmt = ast->asIfStatement(); QVERIFY(stmt != 0); QVERIFY(stmt->condition); } void tst_AST::if_else_statement() { QSharedPointer unit(parseStatement("if (a) b; else c;")); AST *ast = unit->ast(); QVERIFY(ast != 0); IfStatementAST *stmt = ast->asIfStatement(); QVERIFY(stmt != 0); QCOMPARE(stmt->if_token, 1U); QCOMPARE(stmt->lparen_token, 2U); QVERIFY(stmt->condition != 0); QCOMPARE(stmt->rparen_token, 4U); QVERIFY(stmt->statement != 0); QCOMPARE(stmt->else_token, 7U); QVERIFY(stmt->else_statement != 0); // check the `then' statement ExpressionStatementAST *then_stmt = stmt->statement->asExpressionStatement(); QVERIFY(then_stmt != 0); QVERIFY(then_stmt->expression != 0); QCOMPARE(then_stmt->semicolon_token, 6U); SimpleNameAST *a_id_expr = then_stmt->expression->asIdExpression()->name->asSimpleName(); QVERIFY(a_id_expr != 0); QCOMPARE(a_id_expr->identifier_token, 5U); // check the `then' statement ExpressionStatementAST *else_stmt = stmt->else_statement->asExpressionStatement(); QVERIFY(else_stmt != 0); QVERIFY(else_stmt->expression != 0); QCOMPARE(else_stmt->semicolon_token, 9U); SimpleNameAST *b_id_expr = else_stmt->expression->asIdExpression()->name->asSimpleName(); QVERIFY(b_id_expr != 0); QCOMPARE(b_id_expr->identifier_token, 8U); } void tst_AST::while_statement() { QSharedPointer unit(parseStatement("while (a) { }")); AST *ast = unit->ast(); QVERIFY(ast != 0); WhileStatementAST *stmt = ast->asWhileStatement(); QVERIFY(stmt != 0); QCOMPARE(stmt->while_token, 1U); QCOMPARE(stmt->lparen_token, 2U); QVERIFY(stmt->condition != 0); QCOMPARE(stmt->rparen_token, 4U); QVERIFY(stmt->statement != 0); // check condition QVERIFY(stmt->condition->asIdExpression()->name->asSimpleName() != 0); QCOMPARE(stmt->condition->asIdExpression()->name->asSimpleName()->identifier_token, 3U); // check the `body' statement CompoundStatementAST *body_stmt = stmt->statement->asCompoundStatement(); QVERIFY(body_stmt != 0); QCOMPARE(body_stmt->lbrace_token, 5U); QVERIFY(body_stmt->statement_list == 0); QCOMPARE(body_stmt->rbrace_token, 6U); } void tst_AST::while_condition_statement() { QSharedPointer unit(parseStatement("while (int a = foo) { }")); AST *ast = unit->ast(); QVERIFY(ast != 0); WhileStatementAST *stmt = ast->asWhileStatement(); QVERIFY(stmt != 0); QCOMPARE(stmt->while_token, 1U); QCOMPARE(stmt->lparen_token, 2U); QVERIFY(stmt->condition != 0); QCOMPARE(stmt->rparen_token, 7U); QVERIFY(stmt->statement != 0); // check condition ConditionAST *condition = stmt->condition->asCondition(); QVERIFY(condition != 0); QVERIFY(condition->type_specifier_list != 0); QVERIFY(condition->type_specifier_list->value->asSimpleSpecifier() != 0); QCOMPARE(condition->type_specifier_list->value->asSimpleSpecifier()->specifier_token, 3U); QVERIFY(condition->type_specifier_list->next == 0); QVERIFY(condition->declarator != 0); QVERIFY(condition->declarator->core_declarator != 0); QVERIFY(condition->declarator->core_declarator->asDeclaratorId() != 0); QVERIFY(condition->declarator->core_declarator->asDeclaratorId()->name != 0); QVERIFY(condition->declarator->core_declarator->asDeclaratorId()->name->asSimpleName() != 0); QCOMPARE(condition->declarator->core_declarator->asDeclaratorId()->name->asSimpleName()->identifier_token, 4U); QVERIFY(condition->declarator->postfix_declarator_list == 0); QVERIFY(condition->declarator->initializer != 0); QVERIFY(condition->declarator->initializer->asIdExpression()->name->asSimpleName() != 0); QCOMPARE(condition->declarator->initializer->asIdExpression()->name->asSimpleName()->identifier_token, 6U); // check the `body' statement CompoundStatementAST *body_stmt = stmt->statement->asCompoundStatement(); QVERIFY(body_stmt != 0); QCOMPARE(body_stmt->lbrace_token, 8U); QVERIFY(body_stmt->statement_list == 0); QCOMPARE(body_stmt->rbrace_token, 9U); } void tst_AST::for_statement() { QSharedPointer unit(parseStatement("for (;;) {}")); AST *ast = unit->ast(); QVERIFY(ast != 0); ForStatementAST *stmt = ast->asForStatement(); QVERIFY(stmt != 0); QCOMPARE(stmt->for_token, 1U); QCOMPARE(stmt->lparen_token, 2U); QVERIFY(stmt->initializer != 0); QVERIFY(stmt->initializer->asExpressionStatement() != 0); QCOMPARE(stmt->initializer->asExpressionStatement()->semicolon_token, 3U); QVERIFY(stmt->condition == 0); QCOMPARE(stmt->semicolon_token, 4U); QVERIFY(stmt->expression == 0); QCOMPARE(stmt->rparen_token, 5U); QVERIFY(stmt->statement != 0); QVERIFY(stmt->statement->asCompoundStatement() != 0); QCOMPARE(stmt->statement->asCompoundStatement()->lbrace_token, 6U); QVERIFY(stmt->statement->asCompoundStatement()->statement_list == 0); QCOMPARE(stmt->statement->asCompoundStatement()->rbrace_token, 7U); } void tst_AST::cpp_initializer_or_function_declaration() { QSharedPointer unit(parseStatement("QFileInfo fileInfo(foo);")); AST *ast = unit->ast(); QVERIFY(ast != 0); DeclarationStatementAST *stmt = ast->asDeclarationStatement(); QVERIFY(stmt != 0); QVERIFY(stmt->declaration != 0); SimpleDeclarationAST *simple_decl = stmt->declaration->asSimpleDeclaration(); QVERIFY(simple_decl != 0); QVERIFY(simple_decl->decl_specifier_list != 0); QVERIFY(simple_decl->decl_specifier_list->next == 0); QVERIFY(simple_decl->declarator_list != 0); QVERIFY(simple_decl->declarator_list->next == 0); QCOMPARE(simple_decl->semicolon_token, 6U); NamedTypeSpecifierAST *named_ty = simple_decl->decl_specifier_list->value->asNamedTypeSpecifier(); QVERIFY(named_ty != 0); QVERIFY(named_ty->name != 0); SimpleNameAST *simple_named_ty = named_ty->name->asSimpleName(); QVERIFY(simple_named_ty != 0); QCOMPARE(simple_named_ty->identifier_token, 1U); DeclaratorAST *declarator = simple_decl->declarator_list->value; QVERIFY(declarator != 0); QVERIFY(declarator->core_declarator != 0); QVERIFY(declarator->postfix_declarator_list != 0); QVERIFY(declarator->postfix_declarator_list->next == 0); QVERIFY(declarator->initializer == 0); DeclaratorIdAST *decl_id = declarator->core_declarator->asDeclaratorId(); QVERIFY(decl_id != 0); QVERIFY(decl_id->name != 0); QVERIFY(decl_id->name->asSimpleName() != 0); QCOMPARE(decl_id->name->asSimpleName()->identifier_token, 2U); FunctionDeclaratorAST *fun_declarator = declarator->postfix_declarator_list->value->asFunctionDeclarator(); QVERIFY(fun_declarator != 0); QCOMPARE(fun_declarator->lparen_token, 3U); QVERIFY(fun_declarator->parameter_declaration_clause != 0); QCOMPARE(fun_declarator->rparen_token, 5U); // check the formal arguments ParameterDeclarationClauseAST *param_clause = fun_declarator->parameter_declaration_clause; QVERIFY(param_clause->parameter_declaration_list != 0); QVERIFY(param_clause->parameter_declaration_list->next == 0); QCOMPARE(param_clause->dot_dot_dot_token, 0U); // check the parameter ParameterDeclarationListAST *declarations = param_clause->parameter_declaration_list; QVERIFY(declarations); QVERIFY(declarations->value); QVERIFY(! declarations->next); ParameterDeclarationAST *param = declarations->value->asParameterDeclaration(); QVERIFY(param); QVERIFY(param->type_specifier_list != 0); QVERIFY(param->type_specifier_list->next == 0); QVERIFY(param->type_specifier_list->value->asNamedTypeSpecifier() != 0); QVERIFY(param->type_specifier_list->value->asNamedTypeSpecifier()->name != 0); QVERIFY(param->type_specifier_list->value->asNamedTypeSpecifier()->name->asSimpleName() != 0); QCOMPARE(param->type_specifier_list->value->asNamedTypeSpecifier()->name->asSimpleName()->identifier_token, 4U); } void tst_AST::cpp_constructor_one_unamed_arg() { QSharedPointer unit(parseDeclaration("QFileInfo::QFileInfo(QString /*name*/) {}")); AST *ast = unit->ast(); QVERIFY(ast != 0); FunctionDefinitionAST *funDef = ast->asFunctionDefinition(); QVERIFY(funDef != 0); QVERIFY(funDef->declarator != 0); QVERIFY(funDef->declarator->postfix_declarator_list != 0); QVERIFY(funDef->declarator->postfix_declarator_list->lastValue() != 0); FunctionDeclaratorAST *funDecl = funDef->declarator->postfix_declarator_list->lastValue()->asFunctionDeclarator(); QVERIFY(funDecl != 0); QVERIFY(funDecl->parameter_declaration_clause != 0); QVERIFY(funDecl->parameter_declaration_clause->parameter_declaration_list != 0); } void tst_AST::cpp_constructor_one_unamed_arg_namespace() { QSharedPointer unit(parseDeclaration("Foo::QFileInfo::QFileInfo(QString /*name*/) {}")); AST *ast = unit->ast(); QVERIFY(ast != 0); FunctionDefinitionAST *funDef = ast->asFunctionDefinition(); QVERIFY(funDef != 0); QVERIFY(funDef->declarator != 0); QVERIFY(funDef->declarator->postfix_declarator_list != 0); QVERIFY(funDef->declarator->postfix_declarator_list->lastValue() != 0); FunctionDeclaratorAST *funDecl = funDef->declarator->postfix_declarator_list->lastValue()->asFunctionDeclarator(); QVERIFY(funDecl != 0); QVERIFY(funDecl->parameter_declaration_clause != 0); QVERIFY(funDecl->parameter_declaration_clause->parameter_declaration_list != 0); } void tst_AST::cpp_constructor_one_named_arg() { QSharedPointer unit(parseDeclaration("QFileInfo::QFileInfo(QString name) {}")); AST *ast = unit->ast(); QVERIFY(ast != 0); FunctionDefinitionAST *funDef = ast->asFunctionDefinition(); QVERIFY(funDef != 0); QVERIFY(funDef->declarator != 0); QVERIFY(funDef->declarator->postfix_declarator_list != 0); QVERIFY(funDef->declarator->postfix_declarator_list->lastValue() != 0); FunctionDeclaratorAST *funDecl = funDef->declarator->postfix_declarator_list->lastValue()->asFunctionDeclarator(); QVERIFY(funDecl != 0); QVERIFY(funDecl->parameter_declaration_clause != 0); QVERIFY(funDecl->parameter_declaration_clause->parameter_declaration_list != 0); } void tst_AST::cpp_constructor_one_knowntype_arg() { QSharedPointer unit(parseDeclaration("QFileInfo::QFileInfo(int /*name*/) {}")); AST *ast = unit->ast(); QVERIFY(ast != 0); FunctionDefinitionAST *funDef = ast->asFunctionDefinition(); QVERIFY(funDef != 0); QVERIFY(funDef->declarator != 0); QVERIFY(funDef->declarator->postfix_declarator_list != 0); QVERIFY(funDef->declarator->postfix_declarator_list->lastValue() != 0); FunctionDeclaratorAST *funDecl = funDef->declarator->postfix_declarator_list->lastValue()->asFunctionDeclarator(); QVERIFY(funDecl != 0); QVERIFY(funDecl->parameter_declaration_clause != 0); QVERIFY(funDecl->parameter_declaration_clause->parameter_declaration_list != 0); } void tst_AST::cpp_constructor_one_const_arg() { QSharedPointer unit(parseDeclaration("QFileInfo::QFileInfo(const QString /*name*/) {}")); AST *ast = unit->ast(); QVERIFY(ast != 0); FunctionDefinitionAST *funDef = ast->asFunctionDefinition(); QVERIFY(funDef != 0); QVERIFY(funDef->declarator != 0); QVERIFY(funDef->declarator->postfix_declarator_list != 0); QVERIFY(funDef->declarator->postfix_declarator_list->lastValue() != 0); FunctionDeclaratorAST *funDecl = funDef->declarator->postfix_declarator_list->lastValue()->asFunctionDeclarator(); QVERIFY(funDecl != 0); QVERIFY(funDecl->parameter_declaration_clause != 0); QVERIFY(funDecl->parameter_declaration_clause->parameter_declaration_list != 0); } void tst_AST::cpp_constructor_one_ref_arg() { QSharedPointer unit(parseDeclaration("QFileInfo::QFileInfo(QString & /*name*/) {}")); AST *ast = unit->ast(); QVERIFY(ast != 0); FunctionDefinitionAST *funDef = ast->asFunctionDefinition(); QVERIFY(funDef != 0); QVERIFY(funDef->declarator != 0); QVERIFY(funDef->declarator->postfix_declarator_list != 0); QVERIFY(funDef->declarator->postfix_declarator_list->lastValue() != 0); FunctionDeclaratorAST *funDecl = funDef->declarator->postfix_declarator_list->lastValue()->asFunctionDeclarator(); QVERIFY(funDecl != 0); QVERIFY(funDecl->parameter_declaration_clause != 0); QVERIFY(funDecl->parameter_declaration_clause->parameter_declaration_list != 0); } void tst_AST::cpp_constructor_no_arg() { QSharedPointer unit(parseDeclaration("QFileInfo::QFileInfo() {}")); AST *ast = unit->ast(); QVERIFY(ast != 0); FunctionDefinitionAST *funDef = ast->asFunctionDefinition(); QVERIFY(funDef != 0); QVERIFY(funDef->declarator != 0); QVERIFY(funDef->declarator->postfix_declarator_list != 0); QVERIFY(funDef->declarator->postfix_declarator_list->lastValue() != 0); FunctionDeclaratorAST *funDecl = funDef->declarator->postfix_declarator_list->lastValue()->asFunctionDeclarator(); QVERIFY(funDecl != 0); QVERIFY(funDecl->parameter_declaration_clause == 0); } void tst_AST::cpp_constructor_multiple_args() { QSharedPointer unit(parseDeclaration("QFileInfo::QFileInfo(QString /*name*/, QString /*type*/) {}")); AST *ast = unit->ast(); QVERIFY(ast != 0); FunctionDefinitionAST *funDef = ast->asFunctionDefinition(); QVERIFY(funDef != 0); QVERIFY(funDef->declarator != 0); QVERIFY(funDef->declarator->postfix_declarator_list != 0); QVERIFY(funDef->declarator->postfix_declarator_list->lastValue() != 0); FunctionDeclaratorAST *funDecl = funDef->declarator->postfix_declarator_list->lastValue()->asFunctionDeclarator(); QVERIFY(funDecl != 0); QVERIFY(funDecl->parameter_declaration_clause != 0); QVERIFY(funDecl->parameter_declaration_clause->parameter_declaration_list != 0); } void tst_AST::cpp_constructor_function_try_catch() { QSharedPointer unit(parseDeclaration("QFileInfo::QFileInfo(QString name, QString type)" " try : m_name(name), m_type(type) {}" " catch (...) {}")); AST *ast = unit->ast(); QVERIFY(ast != 0); FunctionDefinitionAST *funDef = ast->asFunctionDefinition(); QVERIFY(funDef != 0); QVERIFY(funDef->ctor_initializer != 0); QVERIFY(funDef->declarator != 0); QVERIFY(funDef->declarator->postfix_declarator_list != 0); QVERIFY(funDef->declarator->postfix_declarator_list->lastValue() != 0); FunctionDeclaratorAST *funDecl = funDef->declarator->postfix_declarator_list->lastValue()->asFunctionDeclarator(); QVERIFY(funDecl != 0); QVERIFY(funDecl->parameter_declaration_clause != 0); QVERIFY(funDecl->parameter_declaration_clause->parameter_declaration_list != 0); } void tst_AST::cpp11_variadic_inheritance() { QSharedPointer unit(parseDeclaration( "template class C : public Args... {};", false, false, true)); AST *ast = unit->ast(); QVERIFY(ast != 0); DeclarationAST *d = ast->asDeclaration(); QVERIFY(d != 0); TemplateDeclarationAST *t = d->asTemplateDeclaration(); QVERIFY(t != 0); DeclarationListAST *tp = t->template_parameter_list; QVERIFY(tp != 0); QVERIFY(tp->next == 0); DeclarationAST *d3 = tp->value; QVERIFY(d3 != 0); TypenameTypeParameterAST *ttp = d3->asTypenameTypeParameter(); QVERIFY(ttp != 0); QVERIFY(ttp->dot_dot_dot_token != 0); // important DeclarationAST *d2 = t->declaration; QVERIFY(d2 != 0); SimpleDeclarationAST *sd = d2->asSimpleDeclaration(); QVERIFY(sd != 0); ClassSpecifierAST *cl = sd->decl_specifier_list->value->asClassSpecifier(); QVERIFY(cl != 0); BaseSpecifierListAST *bl = cl->base_clause_list; QVERIFY(bl != 0); QVERIFY(bl->next == 0); BaseSpecifierAST *ba = bl->value; QVERIFY(ba != 0); QVERIFY(ba->ellipsis_token != 0); // important } void tst_AST::cpp_qproperty() { QFETCH(QByteArray, source); QVERIFY(!source.isEmpty()); const QByteArray sourceWithinClass = "class C { " + source + " };"; QSharedPointer unit(parseDeclaration(sourceWithinClass, false, true)); QVERIFY(unit->ast()); QCOMPARE(diag.errorCount, 0); } void tst_AST::cpp_qproperty_data() { QTest::addColumn("source"); QTest::newRow("read-final") << QByteArray("Q_PROPERTY(bool focus READ hasFocus FINAL)"); QTest::newRow("read-write-final") << QByteArray("Q_PROPERTY(bool focus READ hasFocus WRITE setFocus FINAL)"); QTest::newRow("member-final") << QByteArray("Q_PROPERTY(bool focus MEMBER m_focus FINAL)"); QTest::newRow("member-read-final") << QByteArray("Q_PROPERTY(bool focus MEMBER m_focus READ m_focus FINAL)"); QTest::newRow("member-read-write-final") << QByteArray("Q_PROPERTY(bool focus MEMBER m_focus READ hasFocus WRITE setFocus FINAL)"); QTest::newRow("all") << QByteArray("Q_PROPERTY(bool focus MEMBER m_focus READ hasFocus WRITE setFocus" " RESET resetFocus NOTIFY focusChanged REVISION 1 DESIGNABLE true" " SCRIPTABLE true STORED true USER true CONSTANT FINAL)"); } void tst_AST::objc_simple_class() { QSharedPointer unit(parseDeclaration("\n" "@interface Zoo {} +(id)alloc;-(id)init;@end\n" "@implementation Zoo\n" "+(id)alloc{}\n" "-(id)init{}\n" "@end\n" )); AST *ast = unit->ast(); QVERIFY(ast); } void tst_AST::objc_attributes_followed_by_at_keyword() { QSharedPointer unit(parseDeclaration("\n" "__attribute__((deprecated)) @interface foo \n" "{\n" " int a, b;\n" "}\n" "+ (id) init;\n" "- (id) init:(int)a foo:(int)b, c;\n" "@end\n" )); AST *ast = unit->ast(); QVERIFY(ast); } void tst_AST::objc_protocol_forward_declaration_1() { QSharedPointer unit(parseDeclaration("\n@protocol foo;")); AST *ast = unit->ast(); QVERIFY(ast); } void tst_AST::objc_protocol_definition_1() { QSharedPointer unit(parseDeclaration("\n@protocol foo @end")); AST *ast = unit->ast(); QVERIFY(ast); } void tst_AST::objc_method_attributes_1() { QSharedPointer unit(parseDeclaration("\n" "@interface Zoo\n" "- (void) foo __attribute__((deprecated));\n" "+ (void) bar __attribute__((unavailable));\n" "@end\n" )); AST *ast = unit->ast(); QVERIFY(ast); ObjCClassDeclarationAST *zoo = ast->asObjCClassDeclaration(); QVERIFY(zoo); QVERIFY(zoo->interface_token); QVERIFY(! (zoo->implementation_token)); QVERIFY(zoo->class_name); QVERIFY(zoo->class_name->asSimpleName()); QCOMPARE(unit->spell(zoo->class_name->asSimpleName()->identifier_token), "Zoo"); DeclarationListAST *decls = zoo->member_declaration_list; QVERIFY(decls->value); QVERIFY(decls->next); QVERIFY(decls->next->value); QVERIFY(! (decls->next->next)); ObjCMethodDeclarationAST *fooDecl = decls->value->asObjCMethodDeclaration(); QVERIFY(fooDecl); QVERIFY(! (fooDecl->function_body)); QVERIFY(fooDecl->semicolon_token); ObjCMethodPrototypeAST *foo = fooDecl->method_prototype; QVERIFY(foo); QCOMPARE(unit->tokenKind(foo->method_type_token), T_MINUS); QVERIFY(foo->type_name); QVERIFY(foo->selector); QVERIFY(foo->selector->selector_argument_list->value); QVERIFY(!foo->selector->selector_argument_list->next); QCOMPARE(unit->spell(foo->selector->selector_argument_list->value->name_token), "foo"); QVERIFY(foo->attribute_list); QVERIFY(foo->attribute_list->value); QVERIFY(! (foo->attribute_list->next)); GnuAttributeSpecifierAST *deprecatedSpec = foo->attribute_list->value->asGnuAttributeSpecifier(); QVERIFY(deprecatedSpec); QCOMPARE(unit->tokenKind(deprecatedSpec->attribute_token), T___ATTRIBUTE__); QVERIFY(deprecatedSpec->attribute_list); QVERIFY(deprecatedSpec->attribute_list->value); QVERIFY(! (deprecatedSpec->attribute_list->next)); GnuAttributeAST *deprecatedAttr = deprecatedSpec->attribute_list->value->asGnuAttribute(); QVERIFY(deprecatedAttr); QVERIFY(! deprecatedAttr->expression_list); QCOMPARE(unit->spell(deprecatedAttr->identifier_token), "deprecated"); ObjCMethodDeclarationAST *barDecl = decls->next->value->asObjCMethodDeclaration(); QVERIFY(barDecl); QVERIFY(! (barDecl->function_body)); QVERIFY(barDecl->semicolon_token); ObjCMethodPrototypeAST *bar = barDecl->method_prototype; QVERIFY(bar); QCOMPARE(unit->tokenKind(bar->method_type_token), T_PLUS); QVERIFY(bar->type_name); QVERIFY(bar->selector); QVERIFY(bar->selector->selector_argument_list); QVERIFY(bar->selector->selector_argument_list->value); QVERIFY(!bar->selector->selector_argument_list->next); QCOMPARE(unit->spell(bar->selector->selector_argument_list->value->name_token), "bar"); QVERIFY(bar->attribute_list); QVERIFY(bar->attribute_list->value); QVERIFY(! (bar->attribute_list->next)); GnuAttributeSpecifierAST *unavailableSpec = bar->attribute_list->value->asGnuAttributeSpecifier(); QVERIFY(unavailableSpec); QCOMPARE(unit->tokenKind(unavailableSpec->attribute_token), T___ATTRIBUTE__); QVERIFY(unavailableSpec->attribute_list); QVERIFY(unavailableSpec->attribute_list->value); QVERIFY(! (unavailableSpec->attribute_list->next)); GnuAttributeAST *unavailableAttr = unavailableSpec->attribute_list->value->asGnuAttribute(); QVERIFY(unavailableAttr); QVERIFY(! unavailableAttr->expression_list); QCOMPARE(unit->spell(unavailableAttr->identifier_token), "unavailable"); } /* @selector(foo) @selector(foo:) @selector(foo:bar:) ... */ void tst_AST::objc_selector_error_recovery_1() { QSharedPointer unit(parseDeclaration("\n" "void tst() {\n" " @selector(foo:\n" " int i = 1;\n" "}\n" )); AST *ast = unit->ast(); QVERIFY(ast); } void tst_AST::objc_selector_error_recovery_2() { QSharedPointer unit(parseDeclaration("\n" "void tst() {\n" " @selector(foo:bar);\n" "}\n" )); AST *ast = unit->ast(); QVERIFY(ast); } void tst_AST::objc_try_statement_1() { QSharedPointer unit( parseDeclaration( "\n" "void tst() {\n" " @try {\n" " something();\n" " }\n" "}\n" )); AST *ast = unit->ast(); QVERIFY(ast); QCOMPARE(diag.errorCount, 0); } void tst_AST::objc_try_statement_2() { QSharedPointer unit( parseDeclaration( "void tst() {\n" " @try {\n" " something();\n" " } @catch (NSException *e) {\n" " another_thing();\n" " } @catch (UIException *e) { \n" " one_more_thing();\n" " } @finally {\n" " nothing();\n" " }\n" "}\n" )); AST *ast = unit->ast(); QVERIFY(ast); QCOMPARE(diag.errorCount, 0); } void tst_AST::objc_try_statement_3() { QSharedPointer unit( parseDeclaration( "void tst() {\n" " @try {\n" " get_banana();\n" " } @catch (...) {\n" " printf(\"Oek?\");\n" " }\n" "}\n" )); AST *ast = unit->ast(); QVERIFY(ast); QCOMPARE(diag.errorCount, 0); } void tst_AST::objc_throw_statement() { QSharedPointer unit( parseDeclaration( "void tst() {\n" " NSException *up = [NSException exceptionWithName:@\"NoException\"\n" " reason:@\"No Reason :-)\"\n" " userInfo:nil];\n" " @throw up;\n" "}\n" )); AST *ast = unit->ast(); QVERIFY(ast); QCOMPARE(diag.errorCount, 0); } void tst_AST::normal_array_access() { QSharedPointer unit(parseDeclaration("\n" "int f() {\n" " int a[10];\n" " int b = 1;\n" " return a[b];\n" "}" )); AST *ast = unit->ast(); QVERIFY(ast); FunctionDefinitionAST *func = ast->asFunctionDefinition(); QVERIFY(func); StatementListAST *bodyStatements = func->function_body->asCompoundStatement()->statement_list; QVERIFY(bodyStatements); QVERIFY(bodyStatements->next); QVERIFY(bodyStatements->next->next); QVERIFY(bodyStatements->next->next->value); ExpressionAST *expr = bodyStatements->next->next->value->asReturnStatement()->expression; QVERIFY(expr); ArrayAccessAST *arrayExpr = expr->asArrayAccess(); QVERIFY(arrayExpr); { // check the left-hand side: ExpressionAST *lhs = arrayExpr->base_expression; QVERIFY(lhs); SimpleNameAST *a = lhs->asIdExpression()->name->asSimpleName(); QVERIFY(a); QCOMPARE(QLatin1String(unit->identifier(a->identifier_token)->chars()), QLatin1String("a")); } { // check the right-hand side: QVERIFY(arrayExpr->expression); SimpleNameAST *b = arrayExpr->expression->asIdExpression()->name->asSimpleName(); QVERIFY(b); QCOMPARE(QLatin1String(unit->identifier(b->identifier_token)->chars()), QLatin1String("b")); } } void tst_AST::array_access_with_nested_expression() { QSharedPointer unit(parseDeclaration("\n" "int f() {\n" " int a[15];\n" " int b = 1;\n" " return (a)[b];\n" "}" )); AST *ast = unit->ast(); QVERIFY(ast); FunctionDefinitionAST *func = ast->asFunctionDefinition(); QVERIFY(func); StatementListAST *bodyStatements = func->function_body->asCompoundStatement()->statement_list; QVERIFY(bodyStatements && bodyStatements->next && bodyStatements->next->next && bodyStatements->next->next->value); ExpressionAST *expr = bodyStatements->next->next->value->asReturnStatement()->expression; QVERIFY(expr); CastExpressionAST *castExpr = expr->asCastExpression(); QVERIFY(!castExpr); ArrayAccessAST *arrayExpr = expr->asArrayAccess(); QVERIFY(arrayExpr); { // check the LHS: ExpressionAST *lhs = arrayExpr->base_expression; QVERIFY(lhs); NestedExpressionAST *nested_a = lhs->asNestedExpression(); QVERIFY(nested_a && nested_a->expression); SimpleNameAST *a = nested_a->expression->asIdExpression()->name->asSimpleName(); QVERIFY(a); QCOMPARE(QLatin1String(unit->identifier(a->identifier_token)->chars()), QLatin1String("a")); } { // check the RHS: QVERIFY(arrayExpr->expression); SimpleNameAST *b = arrayExpr->expression->asIdExpression()->name->asSimpleName(); QVERIFY(b); QCOMPARE(QLatin1String(unit->identifier(b->identifier_token)->chars()), QLatin1String("b")); } } void tst_AST::objc_msg_send_expression() { QSharedPointer unit(parseDeclaration("\n" "int f() {\n" " NSObject *obj = [[[NSObject alloc] init] autorelease];\n" " return [obj description];\n" "}" )); AST *ast = unit->ast(); QVERIFY(ast); FunctionDefinitionAST *func = ast->asFunctionDefinition(); QVERIFY(func); StatementListAST *bodyStatements = func->function_body->asCompoundStatement()->statement_list; QVERIFY(bodyStatements && bodyStatements->next && !bodyStatements->next->next && bodyStatements->next->value); {// check the NSObject declaration DeclarationStatementAST *firstStatement = bodyStatements->value->asDeclarationStatement(); QVERIFY(firstStatement); DeclarationAST *objDecl = firstStatement->declaration; QVERIFY(objDecl); SimpleDeclarationAST *simpleDecl = objDecl->asSimpleDeclaration(); QVERIFY(simpleDecl); {// check the type (NSObject) QVERIFY(simpleDecl->decl_specifier_list && !simpleDecl->decl_specifier_list->next); NamedTypeSpecifierAST *namedType = simpleDecl->decl_specifier_list->value->asNamedTypeSpecifier(); QVERIFY(namedType && namedType->name); SimpleNameAST *typeName = namedType->name->asSimpleName(); QVERIFY(typeName); QCOMPARE(QLatin1String(unit->identifier(typeName->identifier_token)->chars()), QLatin1String("NSObject")); } {// check the assignment QVERIFY(simpleDecl->declarator_list && !simpleDecl->declarator_list->next); DeclaratorAST *declarator = simpleDecl->declarator_list->value; QVERIFY(declarator); QVERIFY(!declarator->attribute_list); QVERIFY(declarator->ptr_operator_list && !declarator->ptr_operator_list->next && declarator->ptr_operator_list->value->asPointer() && ! declarator->ptr_operator_list->value->asPointer()->cv_qualifier_list); QVERIFY(declarator->core_declarator && declarator->core_declarator->asDeclaratorId()); NameAST *objNameId = declarator->core_declarator->asDeclaratorId()->name; QVERIFY(objNameId && objNameId->asSimpleName()); QCOMPARE(QLatin1String(unit->identifier(objNameId->asSimpleName()->identifier_token)->chars()), QLatin1String("obj")); QVERIFY(!declarator->postfix_declarator_list); QVERIFY(!declarator->post_attribute_list); ExpressionAST *initializer = declarator->initializer; QVERIFY(initializer); ObjCMessageExpressionAST *expr1 = initializer->asObjCMessageExpression(); QVERIFY(expr1 && expr1->receiver_expression && expr1->selector && !expr1->argument_list); ObjCMessageExpressionAST *expr2 = expr1->receiver_expression->asObjCMessageExpression(); QVERIFY(expr2 && expr2->receiver_expression && expr2->selector && !expr2->argument_list); ObjCMessageExpressionAST *expr3 = expr2->receiver_expression->asObjCMessageExpression(); QVERIFY(expr3 && expr3->receiver_expression && expr3->selector && !expr3->argument_list); } } {// check the return statement ExpressionAST *expr = bodyStatements->next->value->asReturnStatement()->expression; QVERIFY(expr); ObjCMessageExpressionAST *msgExpr = expr->asObjCMessageExpression(); QVERIFY(msgExpr); QVERIFY(msgExpr->receiver_expression); SimpleNameAST *receiver = msgExpr->receiver_expression->asIdExpression()->name->asSimpleName(); QVERIFY(receiver); QCOMPARE(QLatin1String(unit->identifier(receiver->identifier_token)->chars()), QLatin1String("obj")); QVERIFY(msgExpr->argument_list == 0); QVERIFY(msgExpr->selector); ObjCSelectorArgumentListAST *args = msgExpr->selector->selector_argument_list; QVERIFY(args); QVERIFY(args->value); QVERIFY(! args->next); QCOMPARE(QLatin1String(unit->identifier(args->value->name_token)->chars()), QLatin1String("description")); } } void tst_AST::objc_msg_send_expression_without_selector() { // This test is to verify that no ObjCMessageExpressionAST element is created as the expression for the return statement. QSharedPointer unit(parseDeclaration("\n" "int f() {\n" " NSObject *obj = [[[NSObject alloc] init] autorelease];\n" " return [obj];\n" "}", true)); AST *ast = unit->ast(); QVERIFY(ast); FunctionDefinitionAST *func = ast->asFunctionDefinition(); QVERIFY(func); StatementListAST *bodyStatements = func->function_body->asCompoundStatement()->statement_list; QVERIFY(bodyStatements && bodyStatements->next); QVERIFY(bodyStatements->next->value); QVERIFY(bodyStatements->next->value->asReturnStatement()); QVERIFY(!bodyStatements->next->value->asReturnStatement()->expression); } void tst_AST::q_enum_1() { QSharedPointer unit(parseDeclaration("\n" "class Tst {\n" "Q_ENUMS(e)\n" "public:\n" "enum e { x, y };\n" "};\n", false, true)); QVERIFY(unit->ast()); SimpleDeclarationAST *tstDecl = unit->ast()->asSimpleDeclaration(); QVERIFY(tstDecl); QVERIFY(! tstDecl->declarator_list); QVERIFY(tstDecl->decl_specifier_list); QVERIFY(tstDecl->decl_specifier_list->value); QVERIFY(! tstDecl->decl_specifier_list->next); ClassSpecifierAST *tst = tstDecl->decl_specifier_list->value->asClassSpecifier(); QVERIFY(tst); QVERIFY(tst->member_specifier_list); QVERIFY(tst->member_specifier_list->value); QtEnumDeclarationAST *qtEnum = tst->member_specifier_list->value->asQtEnumDeclaration(); QVERIFY(qtEnum); QVERIFY(qtEnum->enumerator_list); QVERIFY(qtEnum->enumerator_list->value); QVERIFY(! qtEnum->enumerator_list->next); SimpleNameAST *e = qtEnum->enumerator_list->value->asSimpleName(); QVERIFY(e); QCOMPARE(unit->spell(e->identifier_token), "e"); } void tst_AST::declarationWithNewStatement() { QFETCH(QByteArray, source); QSharedPointer unit(parseStatement(source, true)); AST *ast = unit->ast(); QVERIFY(ast); QVERIFY(ast->asDeclarationStatement()); } void tst_AST::declarationWithNewStatement_data() { QTest::addColumn("source"); typedef QByteArray _; QTest::newRow("withoutParentheses") << _("Foo *foo = new Foo;"); QTest::newRow("withParentheses") << _("Foo *foo = new Foo();"); QTest::newRow("withParenthesesAndOneArgument") << _("Foo *foo = new Foo(1);"); } void tst_AST::incomplete_ast() { QSharedPointer unit(parseStatement("class A { virtual void a() =\n")); AST *ast = unit->ast(); QVERIFY(ast); } static ClassSpecifierAST *classSpecifierInSimpleDeclaration(SimpleDeclarationAST *simpleDeclaration) { Q_ASSERT(simpleDeclaration); SpecifierListAST *specifier = simpleDeclaration->decl_specifier_list; Q_ASSERT(specifier); Q_ASSERT(specifier->value); return specifier->value->asClassSpecifier(); } void tst_AST::unnamed_class() { QFETCH(QByteArray, source); QVERIFY(!source.isEmpty()); QSharedPointer unit(parseDeclaration(source)); QVERIFY(unit->ast()); SimpleDeclarationAST *simpleDeclaration = unit->ast()->asSimpleDeclaration(); QVERIFY(simpleDeclaration); ClassSpecifierAST *clazz = classSpecifierInSimpleDeclaration(simpleDeclaration); QVERIFY(clazz); QVERIFY(clazz->name); QVERIFY(clazz->name->asAnonymousName()); QCOMPARE(diag.errorCount, 0); } void tst_AST::unnamed_class_data() { QTest::addColumn("source"); typedef QByteArray _; QTest::newRow("unnamed-only") << _("class {};"); QTest::newRow("unnamed-derived") << _("class : B {};"); QTest::newRow("unnamed-__attribute__") << _("class __attribute__((aligned(8))){};"); } void tst_AST::expensiveExpression() { QSharedPointer unit(parseStatement( "void f()\n" "{\n" "(g1\n" "(g2\n" "(g3\n" "(g4\n" "(g5\n" "(g6\n" "(g7\n" "(g8\n" "(g9\n" "(g10\n" "(g11\n" "(g12\n" "(g13\n" "(g14\n" "(g15\n" "(g16\n" "(g17\n" "(g18\n" "(g19\n" "(g20\n" "(g21\n" "(g22\n" "(g23\n" "(g24\n" "(g25\n" "(g26\n" "(g27\n" "(g28\n" "(g29\n" "(g30\n" "(g31(0))))))))))))))))))))))))))))))));\n" "}\n")); QVERIFY(unit->ast()); } void tst_AST::invalidCode_data() { QTest::addColumn("source"); typedef QByteArray _; QTest::newRow("simple") << _("static inValidLine()\n"); QTest::newRow("hard") << _("typedef\n" "if_,\n" "if_,\n" "if_,\n" "if_,\n" "if_,\n" "if_,\n" "if_,\n" "if_,\n" "if_,\n" "if_,\n" "if_,\n" "if_,\n" "if_,\n" "if_,\n" "if_,\n" "if_,\n" "if_,\n" "if_,\n" "if_,\n" "if_,\n" "if_,\n" "if_,\n" "if_,\n" "if_,\n" "if_,\n" "if_,\n" "if_,\n" "if_,\n" "if_,\n" "if_,\n" "if_,\n" "if_,\n" "if_,\n" "if_,\n" "if_,\n" "if_,\n" "if_,\n" "if_,\n" "if_ unit(parse(source, TranslationUnit::ParseTranlationUnit, false, false, true)); // Check that we find the class coming after the invalid garbage. QVERIFY(unit->ast()); TranslationUnitAST *unitAST = unit->ast()->asTranslationUnit(); QVERIFY(unitAST->declaration_list); QVERIFY(unitAST->declaration_list->value); SimpleDeclarationAST *simpleDecl = unitAST->declaration_list->value->asSimpleDeclaration(); QVERIFY(simpleDecl); QVERIFY(simpleDecl->decl_specifier_list); QVERIFY(simpleDecl->decl_specifier_list->value); ClassSpecifierAST *classSpecifier = simpleDecl->decl_specifier_list->value->asClassSpecifier(); QVERIFY(classSpecifier); QVERIFY(diag.errorCount != 0); } void tst_AST::enumDeclaration() { QSharedPointer unit(parseStatement( //Unnamed "enum { ENUMERATOR0 };\n" "enum Enum { ENUMERATOR1 };\n" "enum EnumWithBase : int { ENUMERATOR2 };\n" "enum enum : int { ENUMERATOR2a };\n" "enum class EnumClass { ENUMERATOR3 = 10 };\n", true)); QVERIFY(unit->ast()); QCOMPARE(diag.errorCount, 0); } void tst_AST::invalidEnumClassDeclaration() { QSharedPointer unit(parseStatement( "enum class operator A { };", true)); QVERIFY(diag.errorCount != 0); } void tst_AST::initTestCase() { control.setDiagnosticClient(&diag); } void tst_AST::cleanup() { diag.errorCount = 0; } void tst_AST::line_and_column_1() { QSharedPointer unit(parseDeclaration("\n" "int i;\n", false, true)); unsigned line, column = 0; QVERIFY(unit->ast()); QVERIFY(unit->tokenAt(1).is(T_INT)); unit->getTokenPosition(1, &line, &column); QEXPECT_FAIL("", "See QTCREATORBUG-9799.", Continue); QCOMPARE(line, 2U); QCOMPARE(column, 1U); } QTEST_APPLESS_MAIN(tst_AST) #include "tst_ast.moc"