diff --git a/src/lsp/cxx/lsp/cxx_document.cc b/src/lsp/cxx/lsp/cxx_document.cc index bfe1b0c2..7acdc5c5 100644 --- a/src/lsp/cxx/lsp/cxx_document.cc +++ b/src/lsp/cxx/lsp/cxx_document.cc @@ -259,7 +259,7 @@ void CxxDocument::parse(std::string source) { if (auto classType = type_cast(objectType)) { auto classSymbol = classType->symbol(); - for (auto member : classSymbol->scope()->symbols()) { + for (auto member : views::members(classSymbol)) { if (!member->name()) continue; auto item = d->completionItems.emplace_back(); item.label(to_string(member->name())); diff --git a/src/parser/CMakeLists.txt b/src/parser/CMakeLists.txt index c7202d4d..ecd017f6 100644 --- a/src/parser/CMakeLists.txt +++ b/src/parser/CMakeLists.txt @@ -18,6 +18,7 @@ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. file(GLOB CXX_INCLUDE_HEADER_FILES cxx/*.h) +file(GLOB CXX_VIEWS_INCLUDE_HEADER_FILES cxx/views/*.h) aux_source_directory(cxx SOURCES) @@ -25,6 +26,9 @@ add_library(cxx-parser ${SOURCES} # generated files keywords-priv.h pp_keywords-priv.h + # headers + ${CXX_INCLUDE_HEADER_FILES} + ${CXX_VIEWS_INCLUDE_HEADER_FILES} ) target_compile_definitions(cxx-parser PUBLIC @@ -85,6 +89,11 @@ install( DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/cxx ) +install( + FILES ${CXX_VIEWS_INCLUDE_HEADER_FILES} + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/cxx/views +) + install( TARGETS cxx-parser EXPORT cxxTargets diff --git a/src/parser/cxx/base_classes.cc b/src/parser/cxx/base_classes.cc new file mode 100644 index 00000000..947a171c --- /dev/null +++ b/src/parser/cxx/base_classes.cc @@ -0,0 +1,21 @@ +// Copyright (c) 2024 Roberto Raggi +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include diff --git a/src/parser/cxx/parser.cc b/src/parser/cxx/parser.cc index 65da4b05..3a88a2e7 100644 --- a/src/parser/cxx/parser.cc +++ b/src/parser/cxx/parser.cc @@ -29,12 +29,12 @@ #include #include #include -#include #include #include #include #include #include +#include #include #include @@ -9868,6 +9868,10 @@ void Parser::parse_base_specifier(BaseSpecifierAST*& yyast) { baseClassSymbol->setVirtual(ast->isVirtual); baseClassSymbol->setSymbol(symbol); + if (symbol) { + baseClassSymbol->setName(symbol->name()); + } + switch (ast->accessSpecifier) { case TokenKind::T_PRIVATE: baseClassSymbol->setAccessSpecifier(AccessSpecifier::kPrivate); diff --git a/src/parser/cxx/scope.h b/src/parser/cxx/scope.h index 15f73d18..e961cad8 100644 --- a/src/parser/cxx/scope.h +++ b/src/parser/cxx/scope.h @@ -21,10 +21,10 @@ #pragma once #include -#include #include #include #include +#include #include @@ -106,6 +106,18 @@ constexpr auto functions = std::views::filter(&Symbol::isFunction) | constexpr auto variables = std::views::filter(&Symbol::isVariable) | std::views::transform(symbol_cast); +inline auto members(Scope* scope) { return std::views::all(scope->symbols()); } + +inline auto members(ScopedSymbol* symbol) { + return std::views::all(symbol->scope()->symbols()); +} + +inline auto find(Scope* scope, const Name* name) { + return scope ? scope->find(name) : SymbolChainView{nullptr}; +} + +constexpr auto named_symbol = std::views::filter(&Symbol::name); + } // namespace views } // namespace cxx diff --git a/src/parser/cxx/symbol_chain_view.cc b/src/parser/cxx/symbol_chain_view.cc index e33dade3..1832fa89 100644 --- a/src/parser/cxx/symbol_chain_view.cc +++ b/src/parser/cxx/symbol_chain_view.cc @@ -18,7 +18,9 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include +#include + +// cxx #include namespace cxx { diff --git a/src/parser/cxx/symbol_instantiation.cc b/src/parser/cxx/symbol_instantiation.cc index 0abbd6d6..1589c49a 100644 --- a/src/parser/cxx/symbol_instantiation.cc +++ b/src/parser/cxx/symbol_instantiation.cc @@ -229,7 +229,7 @@ auto SymbolInstantiation::VisitSymbol::operator()(ClassSymbol* symbol) auto newCtor = self.instantiate(ctor); newSymbol->addConstructor(newCtor); } - for (auto member : symbol->scope()->symbols()) { + for (auto member : views::members(symbol)) { auto newMember = self.instantiate(member); newSymbol->addMember(newMember); } @@ -239,7 +239,7 @@ auto SymbolInstantiation::VisitSymbol::operator()(ClassSymbol* symbol) auto SymbolInstantiation::VisitSymbol::operator()(EnumSymbol* symbol) -> Symbol* { auto newSymbol = self.replacement(symbol); - for (auto member : symbol->scope()->symbols()) { + for (auto member : views::members(symbol)) { auto newMember = self.instantiate(member); newSymbol->addMember(newMember); } @@ -249,7 +249,7 @@ auto SymbolInstantiation::VisitSymbol::operator()(EnumSymbol* symbol) auto SymbolInstantiation::VisitSymbol::operator()(ScopedEnumSymbol* symbol) -> Symbol* { auto newSymbol = self.replacement(symbol); - for (auto member : symbol->scope()->symbols()) { + for (auto member : views::members(symbol)) { auto newMember = self.instantiate(member); newSymbol->addMember(newMember); } @@ -259,7 +259,7 @@ auto SymbolInstantiation::VisitSymbol::operator()(ScopedEnumSymbol* symbol) auto SymbolInstantiation::VisitSymbol::operator()(FunctionSymbol* symbol) -> Symbol* { auto newSymbol = self.replacement(symbol); - for (auto member : symbol->scope()->symbols()) { + for (auto member : views::members(symbol)) { if (member->isBlock()) continue; auto newMember = self.instantiate(member); newSymbol->addMember(newMember); @@ -300,7 +300,7 @@ auto SymbolInstantiation::VisitSymbol::operator()(EnumeratorSymbol* symbol) auto SymbolInstantiation::VisitSymbol::operator()( FunctionParametersSymbol* symbol) -> Symbol* { auto newSymbol = self.replacement(symbol); - for (auto member : symbol->scope()->symbols()) { + for (auto member : views::members(symbol)) { if (member->isBlock()) continue; auto newMember = self.instantiate(member); newSymbol->addMember(newMember); @@ -311,7 +311,7 @@ auto SymbolInstantiation::VisitSymbol::operator()( auto SymbolInstantiation::VisitSymbol::operator()( TemplateParametersSymbol* symbol) -> Symbol* { auto newSymbol = self.replacement(symbol); - for (auto member : symbol->scope()->symbols()) { + for (auto member : views::members(symbol)) { auto newMember = self.instantiate(member); newSymbol->addMember(newMember); } diff --git a/src/parser/cxx/views/base_classes.h b/src/parser/cxx/views/base_classes.h new file mode 100644 index 00000000..a66f836b --- /dev/null +++ b/src/parser/cxx/views/base_classes.h @@ -0,0 +1,106 @@ +// Copyright (c) 2024 Roberto Raggi +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include + +#include +#include + +namespace cxx { + +class BaseClassesView { + public: + explicit BaseClassesView(ClassSymbol* classSymbol) : root_(classSymbol) {} + ~BaseClassesView() = default; + + auto begin() const { return Generator{root_}; } + auto end() const { return std::default_sentinel; } + + private: + class Generator { + public: + using value_type = BaseClassSymbol*; + using difference_type = std::ptrdiff_t; + + explicit Generator(ClassSymbol* classSymbol) { + if (classSymbol) { + for (auto base : classSymbol->baseClasses() | std::views::reverse) { + state_->stack.push(base); + } + } + } + + auto operator*() const -> BaseClassSymbol* { + if (state_->stack.empty()) return nullptr; + return state_->stack.top(); + } + + auto operator++() -> Generator& { + auto base = state_->stack.top(); + state_->stack.pop(); + + if (auto classSymbol = symbol_cast(base->symbol())) { + if (!state_->visited.insert(classSymbol).second) { + return *this; + } + + for (auto base : classSymbol->baseClasses() | std::views::reverse) { + state_->stack.push(base); + } + } + + return *this; + } + + auto operator++(int) -> Generator { + auto tmp = *this; + ++*this; + return tmp; + } + + auto operator==(const std::default_sentinel_t&) const -> bool { + return state_->stack.empty(); + } + + private: + struct State { + std::unordered_set visited; + std::stack stack; + }; + + std::shared_ptr state_ = std::make_shared(); + }; + + private: + ClassSymbol* root_; +}; + +namespace views { + +inline auto base_classes(ClassSymbol* classSymbol) -> BaseClassesView { + return BaseClassesView{classSymbol}; +} + +} // namespace views + +} // namespace cxx diff --git a/src/parser/cxx/symbol_chain_view.h b/src/parser/cxx/views/symbol_chain.h similarity index 100% rename from src/parser/cxx/symbol_chain_view.h rename to src/parser/cxx/views/symbol_chain.h