diff --git a/packages/cxx-frontend/src/AST.ts b/packages/cxx-frontend/src/AST.ts index 36e1b7db..2d4a24b1 100644 --- a/packages/cxx-frontend/src/AST.ts +++ b/packages/cxx-frontend/src/AST.ts @@ -2976,19 +2976,22 @@ export class ClassSpecifierAST extends SpecifierAST { getName(): NameAST | undefined { return AST.from(cxx.getASTSlot(this.getHandle(), 2), this.parser); } + getFinalToken(): Token | undefined { + return Token.from(cxx.getASTSlot(this.getHandle(), 3), this.parser); + } getBaseClause(): BaseClauseAST | undefined { - return AST.from(cxx.getASTSlot(this.getHandle(), 3), this.parser); + return AST.from(cxx.getASTSlot(this.getHandle(), 4), this.parser); } getLbraceToken(): Token | undefined { - return Token.from(cxx.getASTSlot(this.getHandle(), 4), this.parser); + return Token.from(cxx.getASTSlot(this.getHandle(), 5), this.parser); } *getDeclarationList(): Generator { - for (let it = cxx.getASTSlot(this.getHandle(), 5); it; it = cxx.getListNext(it)) { + for (let it = cxx.getASTSlot(this.getHandle(), 6); it; it = cxx.getListNext(it)) { yield AST.from(cxx.getListValue(it), this.parser); } } getRbraceToken(): Token | undefined { - return Token.from(cxx.getASTSlot(this.getHandle(), 6), this.parser); + return Token.from(cxx.getASTSlot(this.getHandle(), 7), this.parser); } } diff --git a/src/frontend/cxx/ast_printer.cc b/src/frontend/cxx/ast_printer.cc index fc03f5f8..1585be13 100644 --- a/src/frontend/cxx/ast_printer.cc +++ b/src/frontend/cxx/ast_printer.cc @@ -1656,6 +1656,10 @@ void ASTPrinter::visit(EnumSpecifierAST* ast) { void ASTPrinter::visit(ClassSpecifierAST* ast) { fmt::print(out_, "{}\n", "class-specifier"); + ++indent_; + fmt::print(out_, "{:{}}", "", indent_ * 2); + fmt::print(out_, "is-final: {}\n", ast->isFinal); + --indent_; if (ast->attributeList) { ++indent_; fmt::print(out_, "{:{}}", "", indent_ * 2); diff --git a/src/parser/cxx/ast.cc b/src/parser/cxx/ast.cc index 4cad433b..2a6f86b9 100644 --- a/src/parser/cxx/ast.cc +++ b/src/parser/cxx/ast.cc @@ -2576,6 +2576,7 @@ auto ClassSpecifierAST::firstSourceLocation() -> SourceLocation { if (auto loc = cxx::firstSourceLocation(classLoc)) return loc; if (auto loc = cxx::firstSourceLocation(attributeList)) return loc; if (auto loc = cxx::firstSourceLocation(name)) return loc; + if (auto loc = cxx::firstSourceLocation(finalLoc)) return loc; if (auto loc = cxx::firstSourceLocation(baseClause)) return loc; if (auto loc = cxx::firstSourceLocation(lbraceLoc)) return loc; if (auto loc = cxx::firstSourceLocation(declarationList)) return loc; @@ -2588,6 +2589,7 @@ auto ClassSpecifierAST::lastSourceLocation() -> SourceLocation { if (auto loc = cxx::lastSourceLocation(declarationList)) return loc; if (auto loc = cxx::lastSourceLocation(lbraceLoc)) return loc; if (auto loc = cxx::lastSourceLocation(baseClause)) return loc; + if (auto loc = cxx::lastSourceLocation(finalLoc)) return loc; if (auto loc = cxx::lastSourceLocation(name)) return loc; if (auto loc = cxx::lastSourceLocation(attributeList)) return loc; if (auto loc = cxx::lastSourceLocation(classLoc)) return loc; diff --git a/src/parser/cxx/ast.fbs b/src/parser/cxx/ast.fbs index bdef00b3..089e30ed 100644 --- a/src/parser/cxx/ast.fbs +++ b/src/parser/cxx/ast.fbs @@ -1354,6 +1354,7 @@ table ClassSpecifier /* SpecifierAST */ { base_clause: BaseClause; declaration_list: [Declaration]; class_loc: SourceLocation; + final_loc: SourceLocation; lbrace_loc: SourceLocation; rbrace_loc: SourceLocation; } diff --git a/src/parser/cxx/ast.h b/src/parser/cxx/ast.h index f9d09742..834eb528 100644 --- a/src/parser/cxx/ast.h +++ b/src/parser/cxx/ast.h @@ -2788,10 +2788,12 @@ class ClassSpecifierAST final : public SpecifierAST { SourceLocation classLoc; List* attributeList = nullptr; NameAST* name = nullptr; + SourceLocation finalLoc; BaseClauseAST* baseClause = nullptr; SourceLocation lbraceLoc; List* declarationList = nullptr; SourceLocation rbraceLoc; + bool isFinal = false; void accept(ASTVisitor* visitor) override { visitor->visit(this); } diff --git a/src/parser/cxx/ast_cloner.cc b/src/parser/cxx/ast_cloner.cc index 9a509a69..0bd3fe52 100644 --- a/src/parser/cxx/ast_cloner.cc +++ b/src/parser/cxx/ast_cloner.cc @@ -3110,6 +3110,8 @@ void ASTCloner::visit(ClassSpecifierAST* ast) { copy->name = accept(ast->name); + copy->finalLoc = ast->finalLoc; + copy->baseClause = accept(ast->baseClause); copy->lbraceLoc = ast->lbraceLoc; @@ -3124,6 +3126,8 @@ void ASTCloner::visit(ClassSpecifierAST* ast) { } copy->rbraceLoc = ast->rbraceLoc; + + copy->isFinal = ast->isFinal; } void ASTCloner::visit(TypenameSpecifierAST* ast) { diff --git a/src/parser/cxx/ast_encoder.cc b/src/parser/cxx/ast_encoder.cc index 38a0a095..5a4c05b2 100644 --- a/src/parser/cxx/ast_encoder.cc +++ b/src/parser/cxx/ast_encoder.cc @@ -4475,6 +4475,8 @@ void ASTEncoder::visit(ClassSpecifierAST* ast) { const auto [name, nameType] = acceptName(ast->name); + auto finalLoc = encodeSourceLocation(ast->finalLoc); + const auto baseClause = accept(ast->baseClause); auto lbraceLoc = encodeSourceLocation(ast->lbraceLoc); @@ -4500,6 +4502,7 @@ void ASTEncoder::visit(ClassSpecifierAST* ast) { builder.add_attribute_list_type(attributeListTypesVector); builder.add_name(name); builder.add_name_type(static_cast(nameType)); + builder.add_final_loc(finalLoc.o); builder.add_base_clause(baseClause.o); builder.add_lbrace_loc(lbraceLoc.o); builder.add_declaration_list(declarationListOffsetsVector); diff --git a/src/parser/cxx/ast_slot.cc b/src/parser/cxx/ast_slot.cc index d5f15aa2..be9406c4 100644 --- a/src/parser/cxx/ast_slot.cc +++ b/src/parser/cxx/ast_slot.cc @@ -3539,24 +3539,28 @@ void ASTSlot::visit(ClassSpecifierAST* ast) { slotKind_ = ASTSlotKind::kNode; break; case 3: + value_ = ast->finalLoc.index(); + slotKind_ = ASTSlotKind::kToken; + break; + case 4: value_ = reinterpret_cast(ast->baseClause); slotKind_ = ASTSlotKind::kNode; break; - case 4: + case 5: value_ = ast->lbraceLoc.index(); slotKind_ = ASTSlotKind::kToken; break; - case 5: + case 6: value_ = reinterpret_cast(ast->declarationList); slotKind_ = ASTSlotKind::kNodeList; break; - case 6: + case 7: value_ = ast->rbraceLoc.index(); slotKind_ = ASTSlotKind::kToken; break; } // switch - slotCount_ = 7; + slotCount_ = 8; } void ASTSlot::visit(TypenameSpecifierAST* ast) { diff --git a/src/parser/cxx/parser.cc b/src/parser/cxx/parser.cc index 4cdc4031..57bcad69 100644 --- a/src/parser/cxx/parser.cc +++ b/src/parser/cxx/parser.cc @@ -237,16 +237,11 @@ auto Parser::parse(UnitAST*& ast) -> bool { return parsed; } -auto Parser::parse_id(const Identifier* id) -> bool { - SourceLocation identifierLoc; - return parse_id(id, identifierLoc); -} - auto Parser::parse_id(const Identifier* id, SourceLocation& loc) -> bool { - SourceLocation location; - if (!match(TokenKind::T_IDENTIFIER, location)) return false; - if (unit->identifier(location) != id) return false; - loc = location; + loc = {}; + if (LA().isNot(TokenKind::T_IDENTIFIER)) return false; + if (unit->identifier(currentLocation()) != id)return false; + loc = consumeToken(); return true; } @@ -336,9 +331,13 @@ auto Parser::parse_module_keyword(SourceLocation& loc) -> bool { return true; } -auto Parser::parse_final() -> bool { return parse_id(final_id); } +auto Parser::parse_final(SourceLocation& loc) -> bool { + return parse_id(final_id, loc); +} -auto Parser::parse_override() -> bool { return parse_id(override_id); } +auto Parser::parse_override(SourceLocation& loc) -> bool { + return parse_id(override_id, loc); +} auto Parser::parse_type_name(NameAST*& yyast) -> bool { const auto start = currentLocation(); @@ -468,7 +467,9 @@ auto Parser::parse_module_head() -> bool { match(TokenKind::T_EXPORT, exportLoc); - const auto is_module = parse_id(module_id); + SourceLocation moduleLoc; + + const auto is_module = parse_id(module_id, moduleLoc); rewind(start); @@ -5405,9 +5406,11 @@ auto Parser::parse_expr_or_braced_init_list(ExpressionAST*& yyast) -> bool { } auto Parser::parse_virt_specifier_seq() -> bool { - if (!parse_virt_specifier()) return false; + SourceLocation finalLoc; + + if (!parse_virt_specifier(finalLoc)) return false; - while (parse_virt_specifier()) { + while (parse_virt_specifier(finalLoc)) { // } @@ -6624,8 +6627,10 @@ auto Parser::parse_class_specifier(SpecifierAST*& yyast) -> bool { List* attributeList = nullptr; NameAST* className = nullptr; BaseClauseAST* baseClause = nullptr; + SourceLocation finalLoc; - if (!parse_class_head(classLoc, attributeList, className, baseClause)) { + if (!parse_class_head(classLoc, attributeList, className, finalLoc, + baseClause)) { class_specifiers_.emplace( start, std::make_tuple(currentLocation(), @@ -6651,9 +6656,14 @@ auto Parser::parse_class_specifier(SpecifierAST*& yyast) -> bool { ast->classLoc = classLoc; ast->attributeList = attributeList; ast->name = className; + ast->finalLoc = finalLoc; ast->baseClause = baseClause; ast->lbraceLoc = lbraceLoc; + if (finalLoc) { + ast->isFinal = true; + } + if (!match(TokenKind::T_RBRACE, ast->rbraceLoc)) { if (!parse_class_body(ast->declarationList)) { parse_error("expected class body"); @@ -6700,14 +6710,14 @@ auto Parser::parse_class_body(List*& yyast) -> bool { auto Parser::parse_class_head(SourceLocation& classLoc, List*& attributeList, - NameAST*& name, BaseClauseAST*& baseClause) - -> bool { + NameAST*& name, SourceLocation& finalLoc, + BaseClauseAST*& baseClause) -> bool { if (!parse_class_key(classLoc)) return false; parse_attribute_specifier_seq(attributeList); if (parse_class_head_name(name)) { - parse_class_virt_specifier(); + parse_class_virt_specifier(finalLoc); } parse_base_clause(baseClause); @@ -6733,8 +6743,8 @@ auto Parser::parse_class_head_name(NameAST*& yyast) -> bool { return true; } -auto Parser::parse_class_virt_specifier() -> bool { - if (!parse_final()) return false; +auto Parser::parse_class_virt_specifier(SourceLocation& finalLoc) -> bool { + if (!parse_final(finalLoc)) return false; return true; } @@ -7028,10 +7038,10 @@ auto Parser::parse_member_declarator(InitDeclaratorAST*& yyast, return true; } -auto Parser::parse_virt_specifier() -> bool { - if (parse_final()) return true; +auto Parser::parse_virt_specifier(SourceLocation& loc) -> bool { + if (parse_final(loc)) return true; - if (parse_override()) return true; + if (parse_override(loc)) return true; return false; } diff --git a/src/parser/cxx/parser.h b/src/parser/cxx/parser.h index 625d65e8..fc9a5f8a 100644 --- a/src/parser/cxx/parser.h +++ b/src/parser/cxx/parser.h @@ -97,7 +97,6 @@ class Parser final { return true; } - auto parse_id(const Identifier* id) -> bool; auto parse_id(const Identifier* id, SourceLocation& loc) -> bool; auto parse_nospace() -> bool; auto parse_greater_greater() -> bool; @@ -107,8 +106,8 @@ class Parser final { auto parse_export_keyword(SourceLocation& loc) -> bool; auto parse_import_keyword(SourceLocation& loc) -> bool; auto parse_module_keyword(SourceLocation& loc) -> bool; - auto parse_final() -> bool; - auto parse_override() -> bool; + auto parse_final(SourceLocation& loc) -> bool; + auto parse_override(SourceLocation& loc) -> bool; auto parse_name_id(NameAST*& yyast) -> bool; auto parse_literal(ExpressionAST*& yyast) -> bool; auto parse_translation_unit(UnitAST*& yyast) -> bool; @@ -383,9 +382,10 @@ class Parser final { auto parse_class_body(List*& yyast) -> bool; auto parse_class_head(SourceLocation& classLoc, List*& attributeList, - NameAST*& name, BaseClauseAST*& baseClause) -> bool; + NameAST*& name, SourceLocation& finalLoc, + BaseClauseAST*& baseClause) -> bool; auto parse_class_head_name(NameAST*& yyast) -> bool; - auto parse_class_virt_specifier() -> bool; + auto parse_class_virt_specifier(SourceLocation& loc) -> bool; auto parse_class_key(SourceLocation& classLoc) -> bool; auto parse_member_specification(DeclarationAST*& yyast) -> bool; auto parse_member_declaration(DeclarationAST*& yyast) -> bool; @@ -395,7 +395,7 @@ class Parser final { const DeclSpecs& specs) -> bool; auto parse_member_declarator(InitDeclaratorAST*& yyast, const DeclSpecs& specs) -> bool; - auto parse_virt_specifier() -> bool; + auto parse_virt_specifier(SourceLocation& loc) -> bool; auto parse_pure_specifier() -> bool; auto parse_conversion_function_id(NameAST*& yyast) -> bool; auto parse_base_clause(BaseClauseAST*& yyast) -> bool; diff --git a/tests/unit_tests/ast/class_definition_01.cc b/tests/unit_tests/ast/class_definition_01.cc index f5b6dc55..dc5b05cd 100644 --- a/tests/unit_tests/ast/class_definition_01.cc +++ b/tests/unit_tests/ast/class_definition_01.cc @@ -18,21 +18,25 @@ class DerivedClass3 : virtual public EmptyClass {}; // CHECK-NEXT: simple-declaration // CHECK-NEXT: decl-specifier-list // CHECK-NEXT: class-specifier +// CHECK-NEXT: is-final: false // CHECK-NEXT: name: simple-name // CHECK-NEXT: identifier: EmptyClass // CHECK-NEXT: simple-declaration // CHECK-NEXT: decl-specifier-list // CHECK-NEXT: class-specifier +// CHECK-NEXT: is-final: false // CHECK-NEXT: name: simple-name // CHECK-NEXT: identifier: OtherEmptyClass // CHECK-NEXT: simple-declaration // CHECK-NEXT: decl-specifier-list // CHECK-NEXT: class-specifier +// CHECK-NEXT: is-final: true // CHECK-NEXT: name: simple-name // CHECK-NEXT: identifier: FinalClass // CHECK-NEXT: simple-declaration // CHECK-NEXT: decl-specifier-list // CHECK-NEXT: class-specifier +// CHECK-NEXT: is-final: false // CHECK-NEXT: name: simple-name // CHECK-NEXT: identifier: DerivedClass // CHECK-NEXT: base-clause: base-clause @@ -43,6 +47,7 @@ class DerivedClass3 : virtual public EmptyClass {}; // CHECK-NEXT: simple-declaration // CHECK-NEXT: decl-specifier-list // CHECK-NEXT: class-specifier +// CHECK-NEXT: is-final: false // CHECK-NEXT: name: simple-name // CHECK-NEXT: identifier: DerivedClass2 // CHECK-NEXT: base-clause: base-clause @@ -56,6 +61,7 @@ class DerivedClass3 : virtual public EmptyClass {}; // CHECK-NEXT: simple-declaration // CHECK-NEXT: decl-specifier-list // CHECK-NEXT: class-specifier +// CHECK-NEXT: is-final: false // CHECK-NEXT: name: simple-name // CHECK-NEXT: identifier: DerivedClass3 // CHECK-NEXT: base-clause: base-clause