From e25a7c07e2f5fac332eb1985a6828f0f208b9157 Mon Sep 17 00:00:00 2001 From: Roberto Raggi Date: Mon, 18 Nov 2024 19:56:16 +0100 Subject: [PATCH] chore: Initial clean up of the Scope and Symbol classes --- src/lsp/cxx/lsp/cxx_document.cc | 2 +- src/parser/cxx/name_lookup.cc | 2 +- src/parser/cxx/parser.cc | 11 ++-- src/parser/cxx/scope.cc | 26 ++------ src/parser/cxx/scope.h | 87 +++++++++++++++----------- src/parser/cxx/symbol_chain_view.cc | 31 +++++++++ src/parser/cxx/symbol_chain_view.h | 66 +++++++++++++++++++ src/parser/cxx/symbol_instantiation.cc | 12 ++-- src/parser/cxx/symbols.cc | 4 -- src/parser/cxx/symbols.h | 49 +++------------ tests/api_tests/test_substitution.cc | 4 +- 11 files changed, 178 insertions(+), 116 deletions(-) create mode 100644 src/parser/cxx/symbol_chain_view.cc create mode 100644 src/parser/cxx/symbol_chain_view.h diff --git a/src/lsp/cxx/lsp/cxx_document.cc b/src/lsp/cxx/lsp/cxx_document.cc index 22feb3f8..bfe1b0c2 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->members()) { + for (auto member : classSymbol->scope()->symbols()) { if (!member->name()) continue; auto item = d->completionItems.emplace_back(); item.label(to_string(member->name())); diff --git a/src/parser/cxx/name_lookup.cc b/src/parser/cxx/name_lookup.cc index df548ae5..85dd369e 100644 --- a/src/parser/cxx/name_lookup.cc +++ b/src/parser/cxx/name_lookup.cc @@ -83,7 +83,7 @@ auto Lookup::lookupHelper(Scope* scope, const Name* name, cache.insert(scope); - for (auto symbol : scope->get(name)) { + for (auto symbol : scope->find(name)) { return symbol; } diff --git a/src/parser/cxx/parser.cc b/src/parser/cxx/parser.cc index c58f29c8..65da4b05 100644 --- a/src/parser/cxx/parser.cc +++ b/src/parser/cxx/parser.cc @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -754,7 +755,7 @@ struct Parser::DeclareSymbol { void operator()(Symbol* symbol) { if (auto f = symbol_cast(symbol)) { - for (Symbol* candidate : scope_->get(symbol->name())) { + for (Symbol* candidate : scope_->find(symbol->name())) { if (auto currentFunction = symbol_cast(candidate)) { auto ovl = control()->newOverloadSetSymbol(candidate->enclosingScope(), {}); @@ -4561,8 +4562,8 @@ auto Parser::enterOrCreateNamespace(const Identifier* identifier, if (!identifier) { namespaceSymbol = parentNamespace->unnamedNamespace(); } else { - auto resolved = - parentScope->get(identifier) | std::views::filter(&Symbol::isNamespace); + auto resolved = parentScope->find(identifier) | + std::views::filter(&Symbol::isNamespace); if (std::ranges::distance(resolved) == 1) { namespaceSymbol = symbol_cast(*std::ranges::begin(resolved)); @@ -9309,7 +9310,7 @@ auto Parser::parse_class_head(ClassHead& classHead) -> bool { if (id && !isTemplateSpecialization) { for (auto previous : - scope_->get(id) | std::views::filter(&Symbol::isClass)) { + scope_->find(id) | std::views::filter(&Symbol::isClass)) { if (auto previousClass = symbol_cast(previous)) { if (previousClass->isComplete()) { parse_error(classHead.name->firstSourceLocation(), @@ -11272,7 +11273,7 @@ auto Parser::convertName(UnqualifiedIdAST* id) -> const Name* { } auto Parser::getFunction(Scope* scope, const Name* name, const Type* type) -> FunctionSymbol* { - for (auto candidate : scope->get(name)) { + for (auto candidate : scope->find(name)) { if (auto function = symbol_cast(candidate)) { if (control_->is_same(function->type(), type)) { return function; diff --git a/src/parser/cxx/scope.cc b/src/parser/cxx/scope.cc index c4bca323..838cc5fd 100644 --- a/src/parser/cxx/scope.cc +++ b/src/parser/cxx/scope.cc @@ -18,8 +18,10 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include #include + +// cxx +#include #include #include @@ -70,17 +72,6 @@ struct AddTemplateSymbol { } // namespace -auto Scope::MemberIterator::operator++() -> MemberIterator& { - symbol_ = symbol_->next(); - return *this; -} - -auto Scope::MemberIterator::operator++(int) -> MemberIterator { - auto it = *this; - symbol_ = symbol_->next(); - return it; -} - Scope::Scope(Scope* parent) : parent_(parent) {} Scope::~Scope() {} @@ -163,25 +154,20 @@ void Scope::replaceSymbol(Symbol* symbol, Symbol* newSymbol) { } } -auto Scope::usingDirectives() const -> const std::vector& { - return usingDirectives_; -} - void Scope::addUsingDirective(Scope* scope) { usingDirectives_.push_back(scope); } -auto Scope::getHelper(const Name* name) const - -> std::pair { +auto Scope::find(const Name* name) const -> SymbolChainView { if (!symbols_.empty()) { const auto h = std::hash{}(name) % buckets_.size(); for (auto symbol = buckets_[h]; symbol; symbol = symbol->link_) { if (symbol->name() == name) { - return {MemberIterator{symbol}, MemberIterator{}}; + return SymbolChainView{symbol}; } } } - return {}; + return SymbolChainView{nullptr}; } } // namespace cxx diff --git a/src/parser/cxx/scope.h b/src/parser/cxx/scope.h index b1933934..15f73d18 100644 --- a/src/parser/cxx/scope.h +++ b/src/parser/cxx/scope.h @@ -21,68 +21,46 @@ #pragma once #include +#include +#include #include #include -#include #include namespace cxx { +class SymbolChainView; + class Scope { public: - class MemberIterator { - public: - using value_type = Symbol*; - using difference_type = std::ptrdiff_t; - - MemberIterator() = default; - explicit MemberIterator(Symbol* symbol) : symbol_(symbol) {} - - auto operator<=>(const MemberIterator&) const = default; - - auto operator*() const -> Symbol* { return symbol_; } - auto operator++() -> MemberIterator&; - auto operator++(int) -> MemberIterator; - - private: - Symbol* symbol_ = nullptr; - }; - explicit Scope(Scope* parent); ~Scope(); [[nodiscard]] auto isEnumScope() const -> bool; [[nodiscard]] auto isTemplateParametersScope() const -> bool; - - [[nodiscard]] auto parent() const -> Scope* { return parent_; } - void setParent(Scope* parent) { parent_ = parent; } - [[nodiscard]] auto enclosingNonTemplateParametersScope() const -> Scope*; + [[nodiscard]] auto parent() const -> Scope* { return parent_; } [[nodiscard]] auto owner() const -> ScopedSymbol* { return owner_; } - void setOwner(ScopedSymbol* owner) { owner_ = owner; } - [[nodiscard]] auto symbols() const -> const std::vector& { - return symbols_; - } + [[nodiscard]] auto symbols() const { return std::views::all(symbols_); } - [[nodiscard]] auto get(const Name* name) const { - auto [first, last] = getHelper(name); - return std::ranges::subrange(first, last); + [[nodiscard]] auto usingDirectives() const { + return std::views::all(usingDirectives_); } - void addSymbol(Symbol* symbol); - void replaceSymbol(Symbol* symbol, Symbol* newSymbol); + [[nodiscard]] auto find(const Name* name) const -> SymbolChainView; - [[nodiscard]] auto usingDirectives() const -> const std::vector&; + void setParent(Scope* parent) { parent_ = parent; } + void setOwner(ScopedSymbol* owner) { owner_ = owner; } + void addSymbol(Symbol* symbol); void addUsingDirective(Scope* scope); - private: - [[nodiscard]] auto getHelper(const Name* name) const - -> std::pair; + void replaceSymbol(Symbol* symbol, Symbol* newSymbol); + private: void rehash(); private: @@ -93,4 +71,41 @@ class Scope { std::vector usingDirectives_; }; +namespace views { + +constexpr auto class_or_namespaces = + std::views::filter(&Symbol::isClassOrNamespace) | + std::views::transform( + [](Symbol* s) { return static_cast(s); }); + +constexpr auto enum_or_scoped_enums = + std::views::filter(&Symbol::isEnumOrScopedEnum) | + std::views::transform( + [](Symbol* s) { return static_cast(s); }); + +constexpr const auto namespaces = + std::views::filter(&Symbol::isNamespace) | + std::views::transform(symbol_cast); + +constexpr auto concepts = std::views::filter(&Symbol::isConcept) | + std::views::transform(symbol_cast); + +constexpr auto classes = std::views::filter(&Symbol::isClass) | + std::views::transform(symbol_cast); + +constexpr auto enums = std::views::filter(&Symbol::isEnum) | + std::views::transform(symbol_cast); + +constexpr auto scoped_enums = + std::views::filter(&Symbol::isScopedEnum) | + std::views::transform(symbol_cast); + +constexpr auto functions = std::views::filter(&Symbol::isFunction) | + std::views::transform(symbol_cast); + +constexpr auto variables = std::views::filter(&Symbol::isVariable) | + std::views::transform(symbol_cast); + +} // namespace views + } // namespace cxx diff --git a/src/parser/cxx/symbol_chain_view.cc b/src/parser/cxx/symbol_chain_view.cc new file mode 100644 index 00000000..e33dade3 --- /dev/null +++ b/src/parser/cxx/symbol_chain_view.cc @@ -0,0 +1,31 @@ +// 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 +#include + +namespace cxx { + +auto SymbolChainView::Generator::operator++() -> Generator& { + symbol_ = symbol_->next(); + return *this; +} + +} // namespace cxx \ No newline at end of file diff --git a/src/parser/cxx/symbol_chain_view.h b/src/parser/cxx/symbol_chain_view.h new file mode 100644 index 00000000..27ae23c1 --- /dev/null +++ b/src/parser/cxx/symbol_chain_view.h @@ -0,0 +1,66 @@ +// 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 + +namespace cxx { + +class SymbolChainView : public std::ranges::view_interface { + public: + explicit SymbolChainView(Symbol* symbol) : symbol_{symbol} {} + + auto begin() const { return Generator{symbol_}; } + auto end() const { return std::default_sentinel; } + + private: + class Generator { + public: + using difference_type = std::ptrdiff_t; + using value_type = Symbol*; + + explicit Generator(Symbol* symbol) : symbol_(symbol) {} + + auto operator*() const -> Symbol* { return symbol_; } + + auto operator++() -> Generator&; + + auto operator++(int) -> Generator { + auto it = *this; + ++*this; + return it; + } + + auto operator==(const std::default_sentinel_t&) const -> bool { + return symbol_ == nullptr; + } + + private: + Symbol* symbol_ = nullptr; + }; + + private: + Symbol* symbol_; +}; + +} // namespace cxx \ No newline at end of file diff --git a/src/parser/cxx/symbol_instantiation.cc b/src/parser/cxx/symbol_instantiation.cc index bb866a21..0abbd6d6 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->members()) { + for (auto member : symbol->scope()->symbols()) { 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->members()) { + for (auto member : symbol->scope()->symbols()) { 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->members()) { + for (auto member : symbol->scope()->symbols()) { 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->members()) { + for (auto member : symbol->scope()->symbols()) { 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->members()) { + for (auto member : symbol->scope()->symbols()) { 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->members()) { + for (auto member : symbol->scope()->symbols()) { auto newMember = self.instantiate(member); newSymbol->addMember(newMember); } diff --git a/src/parser/cxx/symbols.cc b/src/parser/cxx/symbols.cc index 89fef948..fadec161 100644 --- a/src/parser/cxx/symbols.cc +++ b/src/parser/cxx/symbols.cc @@ -88,10 +88,6 @@ ScopedSymbol::~ScopedSymbol() {} auto ScopedSymbol::scope() const -> Scope* { return scope_.get(); } -auto ScopedSymbol::members() const -> const std::vector& { - return scope_->symbols(); -} - void ScopedSymbol::addMember(Symbol* symbol) { scope_->addSymbol(symbol); } NamespaceSymbol::NamespaceSymbol(Scope* enclosingScope) diff --git a/src/parser/cxx/symbols.h b/src/parser/cxx/symbols.h index 69afd7f0..eef97110 100644 --- a/src/parser/cxx/symbols.h +++ b/src/parser/cxx/symbols.h @@ -139,6 +139,14 @@ class Symbol { CXX_FOR_EACH_SYMBOL(PROCESS_SYMBOL) #undef PROCESS_SYMBOL + [[nodiscard]] auto isClassOrNamespace() const -> bool { + return isClass() || isNamespace(); + } + + [[nodiscard]] auto isEnumOrScopedEnum() const -> bool { + return isEnum() || isScopedEnum(); + } + private: friend class Scope; @@ -150,53 +158,12 @@ class Symbol { SourceLocation location_; }; -class SymbolChainIterator { - public: - using difference_type = std::ptrdiff_t; - using value_type = Symbol*; - - SymbolChainIterator() = default; - explicit SymbolChainIterator(Symbol* symbol) : symbol_(symbol) {} - - auto operator*() const -> Symbol* { return symbol_; } - - auto operator++() -> SymbolChainIterator& { - symbol_ = symbol_->next(); - return *this; - } - - auto operator++(int) -> SymbolChainIterator { - auto it = *this; - ++*this; - return it; - } - - auto operator==(const SymbolChainIterator&) const -> bool = default; - - private: - Symbol* symbol_ = nullptr; -}; - -static_assert(std::forward_iterator); - -class SymbolChainView : public std::ranges::view_interface { - public: - explicit SymbolChainView(Symbol* symbol) : begin_{symbol} {} - - auto begin() const -> SymbolChainIterator { return begin_; } - auto end() const -> SymbolChainIterator { return SymbolChainIterator(); } - - private: - SymbolChainIterator begin_; -}; - class ScopedSymbol : public Symbol { public: ScopedSymbol(SymbolKind kind, Scope* enclosingScope); ~ScopedSymbol() override; [[nodiscard]] auto scope() const -> Scope*; - [[nodiscard]] auto members() const -> const std::vector&; void addMember(Symbol* member); diff --git a/tests/api_tests/test_substitution.cc b/tests/api_tests/test_substitution.cc index 11b749df..72bd8fe1 100644 --- a/tests/api_tests/test_substitution.cc +++ b/tests/api_tests/test_substitution.cc @@ -64,7 +64,7 @@ struct Source { auto get(std::string_view name) -> Symbol* { Symbol* symbol = nullptr; auto id = unit.control()->getIdentifier(name); - for (auto candidate : scope()->get(id)) { + for (auto candidate : scope()->find(id)) { if (symbol) return nullptr; symbol = candidate; } @@ -87,7 +87,7 @@ struct LookupMember { auto operator()(Scope* scope, std::string_view name) -> Symbol* { auto id = source.control()->getIdentifier(name); - for (auto candidate : scope->get(id)) { + for (auto candidate : scope->find(id)) { return candidate; } return nullptr;