LCOV - code coverage report
Current view: top level - gcc/rust/resolve - rust-forever-stack.hxx (source / functions) Coverage Total Hit
Test: gcc.info Lines: 90.1 % 142 128
Test Date: 2024-04-27 14:03:13 Functions: 36.4 % 66 24
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : // Copyright (C) 2020-2024 Free Software Foundation, Inc.
       2                 :             : 
       3                 :             : // This file is part of GCC.
       4                 :             : 
       5                 :             : // GCC is free software; you can redistribute it and/or modify it under
       6                 :             : // the terms of the GNU General Public License as published by the Free
       7                 :             : // Software Foundation; either version 3, or (at your option) any later
       8                 :             : // version.
       9                 :             : 
      10                 :             : // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      11                 :             : // WARRANTY; without even the implied warranty of MERCHANTABILITY or
      12                 :             : // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      13                 :             : // for more details.
      14                 :             : 
      15                 :             : // You should have received a copy of the GNU General Public License
      16                 :             : // along with GCC; see the file COPYING3.  If not see
      17                 :             : // <http://www.gnu.org/licenses/>.
      18                 :             : 
      19                 :             : #include "expected.h"
      20                 :             : #include "rust-ast.h"
      21                 :             : #include "rust-diagnostics.h"
      22                 :             : #include "rust-forever-stack.h"
      23                 :             : #include "rust-rib.h"
      24                 :             : #include "optional.h"
      25                 :             : 
      26                 :             : namespace Rust {
      27                 :             : namespace Resolver2_0 {
      28                 :             : 
      29                 :             : template <Namespace N>
      30                 :             : bool
      31                 :       21833 : ForeverStack<N>::Node::is_root () const
      32                 :             : {
      33                 :       21089 :   return !parent.has_value ();
      34                 :             : }
      35                 :             : 
      36                 :             : template <Namespace N>
      37                 :             : bool
      38                 :       21028 : ForeverStack<N>::Node::is_leaf () const
      39                 :             : {
      40                 :       21028 :   return children.empty ();
      41                 :             : }
      42                 :             : 
      43                 :             : template <Namespace N>
      44                 :             : void
      45                 :             : ForeverStack<N>::Node::insert_child (Link link, Node child)
      46                 :             : {
      47                 :             :   auto res = children.insert ({link, child});
      48                 :             : 
      49                 :             :   // Do we want to error if the child already exists? Probably not, right?
      50                 :             :   // That's kinda the point, isn't it. So this method always succeeds, right?
      51                 :             : }
      52                 :             : 
      53                 :             : template <Namespace N>
      54                 :             : void
      55                 :         744 : ForeverStack<N>::push (Rib rib, NodeId id, tl::optional<Identifier> path)
      56                 :             : {
      57                 :         930 :   push_inner (rib, Link (id, path));
      58                 :         744 : }
      59                 :             : 
      60                 :             : template <Namespace N>
      61                 :             : void
      62                 :         744 : ForeverStack<N>::push_inner (Rib rib, Link link)
      63                 :             : {
      64                 :             :   // If the link does not exist, we create it and emplace a new `Node` with the
      65                 :             :   // current node as its parent. `unordered_map::emplace` returns a pair with
      66                 :             :   // the iterator and a boolean. If the value already exists, the iterator
      67                 :             :   // points to it. Otherwise, it points to the newly emplaced value, so we can
      68                 :             :   // just update our cursor().
      69                 :         744 :   auto emplace = cursor ().children.emplace (
      70                 :        1488 :     std::make_pair (link, Node (rib, link.id, cursor ())));
      71                 :             : 
      72                 :         744 :   auto it = emplace.first;
      73                 :         744 :   auto existed = !emplace.second;
      74                 :             : 
      75                 :        1116 :   rust_debug ("inserting link: Link(%d [%s]): existed? %s", link.id,
      76                 :             :               link.path.has_value () ? link.path.value ().as_string ().c_str ()
      77                 :             :                                      : "<anon>",
      78                 :             :               existed ? "yes" : "no");
      79                 :             : 
      80                 :             :   // We update the cursor
      81                 :         744 :   update_cursor (it->second);
      82                 :         744 : }
      83                 :             : 
      84                 :             : template <Namespace N>
      85                 :             : void
      86                 :         744 : ForeverStack<N>::pop ()
      87                 :             : {
      88                 :         744 :   rust_assert (!cursor ().is_root ());
      89                 :             : 
      90                 :         744 :   rust_debug ("popping link");
      91                 :             : 
      92                 :         782 :   for (const auto &kv : cursor ().rib.get_values ())
      93                 :          38 :     rust_debug ("current_rib: k: %s, v: %d", kv.first.c_str (), kv.second);
      94                 :             : 
      95                 :         744 :   if (cursor ().parent.has_value ())
      96                 :         886 :     for (const auto &kv : cursor ().parent.value ().rib.get_values ())
      97                 :         142 :       rust_debug ("new cursor: k: %s, v: %d", kv.first.c_str (), kv.second);
      98                 :             : 
      99                 :         744 :   update_cursor (cursor ().parent.value ());
     100                 :         744 : }
     101                 :             : 
     102                 :             : static tl::expected<NodeId, DuplicateNameError>
     103                 :          45 : insert_inner (Rib &rib, std::string name, NodeId node, bool can_shadow)
     104                 :             : {
     105                 :          45 :   return rib.insert (name, node, can_shadow);
     106                 :             : }
     107                 :             : 
     108                 :             : template <Namespace N>
     109                 :             : tl::expected<NodeId, DuplicateNameError>
     110                 :          39 : ForeverStack<N>::insert (Identifier name, NodeId node)
     111                 :             : {
     112                 :          39 :   auto &innermost_rib = peek ();
     113                 :             : 
     114                 :             :   // So what do we do here - if the Rib has already been pushed in an earlier
     115                 :             :   // pass, we might end up in a situation where it is okay to re-add new names.
     116                 :             :   // Do we just ignore that here? Do we keep track of if the Rib is new or not?
     117                 :             :   // should our cursor have info on the current node like "is it newly pushed"?
     118                 :          39 :   return insert_inner (innermost_rib, name.as_string (), node, false);
     119                 :             : }
     120                 :             : 
     121                 :             : template <Namespace N>
     122                 :             : tl::expected<NodeId, DuplicateNameError>
     123                 :           4 : ForeverStack<N>::insert_at_root (Identifier name, NodeId node)
     124                 :             : {
     125                 :           4 :   auto &root_rib = root.rib;
     126                 :             : 
     127                 :             :   // inserting in the root of the crate is never a shadowing operation, even for
     128                 :             :   // macros
     129                 :           4 :   return insert_inner (root_rib, name.as_string (), node, false);
     130                 :             : }
     131                 :             : 
     132                 :             : // Specialization for Macros and Labels - where we are allowed to shadow
     133                 :             : // existing definitions
     134                 :             : template <>
     135                 :             : inline tl::expected<NodeId, DuplicateNameError>
     136                 :           2 : ForeverStack<Namespace::Macros>::insert (Identifier name, NodeId node)
     137                 :             : {
     138                 :           4 :   return insert_inner (peek (), name.as_string (), node, true);
     139                 :             : }
     140                 :             : 
     141                 :             : template <>
     142                 :             : inline tl::expected<NodeId, DuplicateNameError>
     143                 :           0 : ForeverStack<Namespace::Labels>::insert (Identifier name, NodeId node)
     144                 :             : {
     145                 :           0 :   return insert_inner (peek (), name.as_string (), node, true);
     146                 :             : }
     147                 :             : 
     148                 :             : template <Namespace N>
     149                 :             : Rib &
     150                 :          41 : ForeverStack<N>::peek ()
     151                 :             : {
     152                 :          41 :   return cursor ().rib;
     153                 :             : }
     154                 :             : 
     155                 :             : template <Namespace N>
     156                 :             : const Rib &
     157                 :             : ForeverStack<N>::peek () const
     158                 :             : {
     159                 :             :   return cursor ().rib;
     160                 :             : }
     161                 :             : 
     162                 :             : template <Namespace N>
     163                 :             : void
     164                 :           2 : ForeverStack<N>::reverse_iter (std::function<KeepGoing (Node &)> lambda)
     165                 :             : {
     166                 :           4 :   return reverse_iter (cursor (), lambda);
     167                 :             : }
     168                 :             : 
     169                 :             : template <Namespace N>
     170                 :             : void
     171                 :          22 : ForeverStack<N>::reverse_iter (Node &start,
     172                 :             :                                std::function<KeepGoing (Node &)> lambda)
     173                 :             : {
     174                 :          22 :   auto *tmp = &start;
     175                 :             : 
     176                 :          22 :   while (true)
     177                 :             :     {
     178                 :          44 :       auto keep_going = lambda (*tmp);
     179                 :          44 :       if (keep_going == KeepGoing::No)
     180                 :             :         return;
     181                 :             : 
     182                 :          23 :       if (tmp->is_root ())
     183                 :             :         return;
     184                 :             : 
     185                 :          22 :       tmp = &tmp->parent.value ();
     186                 :             :     }
     187                 :             : }
     188                 :             : 
     189                 :             : template <Namespace N>
     190                 :             : typename ForeverStack<N>::Node &
     191                 :        3775 : ForeverStack<N>::cursor ()
     192                 :             : {
     193                 :        3775 :   return cursor_reference;
     194                 :             : }
     195                 :             : 
     196                 :             : template <Namespace N>
     197                 :             : const typename ForeverStack<N>::Node &
     198                 :             : ForeverStack<N>::cursor () const
     199                 :             : {
     200                 :             :   return cursor_reference;
     201                 :             : }
     202                 :             : 
     203                 :             : template <Namespace N>
     204                 :             : void
     205                 :        1488 : ForeverStack<N>::update_cursor (Node &new_cursor)
     206                 :             : {
     207                 :        1488 :   cursor_reference = new_cursor;
     208                 :             : }
     209                 :             : 
     210                 :             : template <Namespace N>
     211                 :             : tl::optional<NodeId>
     212                 :           2 : ForeverStack<N>::get (const Identifier &name)
     213                 :             : {
     214                 :           2 :   tl::optional<NodeId> resolved_node = tl::nullopt;
     215                 :             : 
     216                 :             :   // TODO: Can we improve the API? have `reverse_iter` return an optional?
     217                 :           6 :   reverse_iter ([&resolved_node, &name] (Node &current) {
     218                 :           4 :     auto candidate = current.rib.get (name.as_string ());
     219                 :             : 
     220                 :           4 :     return candidate.map_or (
     221                 :           4 :       [&resolved_node] (NodeId found) {
     222                 :             :         // for most namespaces, we do not need to care about various ribs - they
     223                 :             :         // are available from all contexts if defined in the current scope, or
     224                 :             :         // an outermore one. so if we do have a candidate, we can return it
     225                 :             :         // directly and stop iterating
     226                 :           1 :         resolved_node = found;
     227                 :             : 
     228                 :             :         return KeepGoing::No;
     229                 :             :       },
     230                 :             :       // if there was no candidate, we keep iterating
     231                 :           4 :       KeepGoing::Yes);
     232                 :             :   });
     233                 :             : 
     234                 :           2 :   return resolved_node;
     235                 :             : }
     236                 :             : 
     237                 :             : template <>
     238                 :           0 : tl::optional<NodeId> inline ForeverStack<Namespace::Labels>::get (
     239                 :             :   const Identifier &name)
     240                 :             : {
     241                 :           0 :   tl::optional<NodeId> resolved_node = tl::nullopt;
     242                 :             : 
     243                 :           0 :   reverse_iter ([&resolved_node, &name] (Node &current) {
     244                 :             :     // looking up for labels cannot go through function ribs
     245                 :             :     // TODO: What other ribs?
     246                 :           0 :     if (current.rib.kind == Rib::Kind::Function)
     247                 :             :       return KeepGoing::No;
     248                 :             : 
     249                 :           0 :     auto candidate = current.rib.get (name.as_string ());
     250                 :             : 
     251                 :             :     // FIXME: Factor this in a function with the generic `get`
     252                 :           0 :     return candidate.map_or (
     253                 :           0 :       [&resolved_node] (NodeId found) {
     254                 :           0 :         resolved_node = found;
     255                 :             : 
     256                 :           0 :         return KeepGoing::No;
     257                 :             :       },
     258                 :             :       KeepGoing::Yes);
     259                 :             :   });
     260                 :             : 
     261                 :           0 :   return resolved_node;
     262                 :             : }
     263                 :             : 
     264                 :             : /* Check if an iterator points to the last element */
     265                 :             : template <typename I, typename C>
     266                 :             : static bool
     267                 :          49 : is_last (const I &iterator, const C &collection)
     268                 :             : {
     269                 :          49 :   return iterator + 1 == collection.end ();
     270                 :             : }
     271                 :             : 
     272                 :             : /* Check if an iterator points to the start of the collection */
     273                 :             : template <typename I, typename C>
     274                 :             : static bool
     275                 :          18 : is_start (const I &iterator, const C &collection)
     276                 :             : {
     277                 :          18 :   return iterator == collection.begin ();
     278                 :             : }
     279                 :             : 
     280                 :             : template <Namespace N>
     281                 :             : typename ForeverStack<N>::Node &
     282                 :          20 : ForeverStack<N>::find_closest_module (Node &starting_point)
     283                 :             : {
     284                 :          20 :   auto *closest_module = &starting_point;
     285                 :             : 
     286                 :          60 :   reverse_iter (starting_point, [&closest_module] (Node &current) {
     287                 :          40 :     if (current.rib.kind == Rib::Kind::Module || current.is_root ())
     288                 :             :       {
     289                 :          20 :         closest_module = &current;
     290                 :          20 :         return KeepGoing::No;
     291                 :             :       }
     292                 :             : 
     293                 :             :     return KeepGoing::Yes;
     294                 :             :   });
     295                 :             : 
     296                 :          20 :   return *closest_module;
     297                 :             : }
     298                 :             : 
     299                 :             : /* If a the given condition is met, emit an error about misused leading path
     300                 :             :  * segments */
     301                 :             : template <typename S>
     302                 :             : static inline bool
     303                 :          38 : check_leading_kw_at_start (const S &segment, bool condition)
     304                 :             : {
     305                 :          38 :   if (condition)
     306                 :           2 :     rust_error_at (
     307                 :             :       segment.get_locus (), ErrorCode::E0433,
     308                 :             :       "leading path segment %qs can only be used at the beginning of a path",
     309                 :           2 :       segment.as_string ().c_str ());
     310                 :             : 
     311                 :          38 :   return condition;
     312                 :             : }
     313                 :             : 
     314                 :             : // we first need to handle the "starting" segments - `super`, `self` or
     315                 :             : // `crate`. we don't need to do anything for `self` and can just skip it. for
     316                 :             : // `crate`, we need to go back to the root of the current stack. for each
     317                 :             : // `super` segment, we go back to the cursor's parent until we reach the
     318                 :             : // correct one or the root.
     319                 :             : template <Namespace N>
     320                 :             : template <typename S>
     321                 :             : tl::optional<typename std::vector<S>::const_iterator>
     322                 :          12 : ForeverStack<N>::find_starting_point (const std::vector<S> &segments,
     323                 :             :                                       Node &starting_point)
     324                 :             : {
     325                 :          12 :   auto iterator = segments.begin ();
     326                 :             : 
     327                 :             :   // If we need to do path segment resolution, then we start
     328                 :             :   // at the closest module. In order to resolve something like `foo::bar!()`, we
     329                 :             :   // need to get back to the surrounding module, and look for a child module
     330                 :             :   // named `foo`.
     331                 :          12 :   if (segments.size () > 1)
     332                 :          12 :     starting_point = find_closest_module (starting_point);
     333                 :             : 
     334                 :          20 :   for (; !is_last (iterator, segments); iterator++)
     335                 :             :     {
     336                 :          18 :       auto &seg = *iterator;
     337                 :          18 :       auto is_self_or_crate
     338                 :          18 :         = seg.is_crate_path_seg () || seg.is_lower_self_seg ();
     339                 :             : 
     340                 :             :       // if we're after the first path segment and meet `self` or `crate`, it's
     341                 :             :       // an error - we should only be seeing `super` keywords at this point
     342                 :          18 :       if (check_leading_kw_at_start (seg, !is_start (iterator, segments)
     343                 :          18 :                                             && is_self_or_crate))
     344                 :           1 :         return tl::nullopt;
     345                 :             : 
     346                 :          17 :       if (seg.is_crate_path_seg ())
     347                 :             :         {
     348                 :           5 :           starting_point = root;
     349                 :           5 :           iterator++;
     350                 :             :           break;
     351                 :             :         }
     352                 :          12 :       if (seg.is_lower_self_seg ())
     353                 :             :         {
     354                 :             :           // do nothing and exit
     355                 :           1 :           iterator++;
     356                 :             :           break;
     357                 :             :         }
     358                 :          19 :       if (seg.is_super_path_seg ())
     359                 :             :         {
     360                 :           9 :           if (starting_point.is_root ())
     361                 :             :             {
     362                 :           1 :               rust_error_at (seg.get_locus (), ErrorCode::E0433,
     363                 :             :                              "too many leading %<super%> keywords");
     364                 :           1 :               return tl::nullopt;
     365                 :             :             }
     366                 :             : 
     367                 :           8 :           starting_point = find_closest_module (starting_point.parent.value ());
     368                 :             :           continue;
     369                 :             :         }
     370                 :             : 
     371                 :             :       // now we've gone through the allowed `crate`, `self` or leading `super`
     372                 :             :       // segments. we can start resolving each segment itself.
     373                 :             :       // if we do see another leading segment, then we can error out.
     374                 :             :       break;
     375                 :             :     }
     376                 :             : 
     377                 :          10 :   return iterator;
     378                 :             : }
     379                 :             : 
     380                 :             : template <Namespace N>
     381                 :             : template <typename S>
     382                 :             : tl::optional<typename ForeverStack<N>::Node &>
     383                 :          10 : ForeverStack<N>::resolve_segments (
     384                 :             :   Node &starting_point, const std::vector<S> &segments,
     385                 :             :   typename std::vector<S>::const_iterator iterator)
     386                 :             : {
     387                 :          10 :   auto *current_node = &starting_point;
     388                 :          30 :   for (; !is_last (iterator, segments); iterator++)
     389                 :             :     {
     390                 :          20 :       auto &seg = *iterator;
     391                 :          20 :       auto str = seg.as_string ();
     392                 :          20 :       rust_debug ("[ARTHUR]: resolving segment part: %s", str.c_str ());
     393                 :             : 
     394                 :             :       // check that we don't encounter *any* leading keywords afterwards
     395                 :          40 :       if (check_leading_kw_at_start (seg, seg.is_crate_path_seg ()
     396                 :          20 :                                             || seg.is_super_path_seg ()
     397                 :          39 :                                             || seg.is_lower_self_seg ()))
     398                 :           1 :         return tl::nullopt;
     399                 :             : 
     400                 :          19 :       tl::optional<typename ForeverStack<N>::Node &> child = tl::nullopt;
     401                 :             : 
     402                 :          19 :       for (auto &kv : current_node->children)
     403                 :             :         {
     404                 :          19 :           auto &link = kv.first;
     405                 :             : 
     406                 :          38 :           if (link.path.map_or (
     407                 :          57 :                 [&str] (Identifier path) {
     408                 :          19 :                   auto &path_str = path.as_string ();
     409                 :          19 :                   return str == path_str;
     410                 :             :                 },
     411                 :             :                 false))
     412                 :             :             {
     413                 :          19 :               child = kv.second;
     414                 :             :               break;
     415                 :             :             }
     416                 :             :         }
     417                 :             : 
     418                 :          19 :       if (!child.has_value ())
     419                 :             :         {
     420                 :           0 :           rust_error_at (seg.get_locus (), ErrorCode::E0433,
     421                 :             :                          "failed to resolve path segment %qs", str.c_str ());
     422                 :           0 :           return tl::nullopt;
     423                 :             :         }
     424                 :             : 
     425                 :          19 :       current_node = &child.value ();
     426                 :             :     }
     427                 :             : 
     428                 :           9 :   return *current_node;
     429                 :             : }
     430                 :             : 
     431                 :             : template <Namespace N>
     432                 :             : template <typename S>
     433                 :             : tl::optional<NodeId>
     434                 :          14 : ForeverStack<N>::resolve_path (const std::vector<S> &segments)
     435                 :             : {
     436                 :             :   // TODO: What to do if segments.empty() ?
     437                 :             : 
     438                 :             :   // if there's only one segment, we just use `get`
     439                 :          14 :   if (segments.size () == 1)
     440                 :           2 :     return get (segments.back ().as_string ());
     441                 :             : 
     442                 :          12 :   auto starting_point = cursor ();
     443                 :             : 
     444                 :          12 :   return find_starting_point (segments, starting_point)
     445                 :          22 :     .and_then ([this, &segments, &starting_point] (
     446                 :             :                  typename std::vector<S>::const_iterator iterator) {
     447                 :          10 :       return resolve_segments (starting_point, segments, iterator);
     448                 :             :     })
     449                 :          21 :     .and_then ([&segments] (Node final_node) {
     450                 :           9 :       return final_node.rib.get (segments.back ().as_string ());
     451                 :             :     });
     452                 :          12 : }
     453                 :             : 
     454                 :             : template <Namespace N>
     455                 :             : tl::optional<std::pair<typename ForeverStack<N>::Node &, std::string>>
     456                 :             : ForeverStack<N>::dfs (ForeverStack<N>::Node &starting_point, NodeId to_find)
     457                 :             : {
     458                 :             :   auto &values = starting_point.rib.get_values ();
     459                 :             : 
     460                 :             :   for (auto &kv : values)
     461                 :             :     if (kv.second == to_find)
     462                 :             :       return {{starting_point, kv.first}};
     463                 :             : 
     464                 :             :   for (auto &child : starting_point.children)
     465                 :             :     {
     466                 :             :       auto candidate = dfs (child.second, to_find);
     467                 :             : 
     468                 :             :       if (candidate.has_value ())
     469                 :             :         return candidate;
     470                 :             :     }
     471                 :             : 
     472                 :             :   return tl::nullopt;
     473                 :             : }
     474                 :             : 
     475                 :             : template <Namespace N>
     476                 :             : tl::optional<Resolver::CanonicalPath>
     477                 :             : ForeverStack<N>::to_canonical_path (NodeId id)
     478                 :             : {
     479                 :             :   // find the id in the current forever stack, starting from the root,
     480                 :             :   // performing either a BFS or DFS once the Node containing the ID is found, go
     481                 :             :   // back up to the root (parent().parent().parent()...) accumulate link
     482                 :             :   // segments reverse them that's your canonical path
     483                 :             : 
     484                 :             :   return dfs (root, id).map ([this, id] (std::pair<Node &, std::string> tuple) {
     485                 :             :     auto containing_node = tuple.first;
     486                 :             :     auto name = tuple.second;
     487                 :             : 
     488                 :             :     auto segments = std::vector<Resolver::CanonicalPath> ();
     489                 :             : 
     490                 :             :     reverse_iter (containing_node, [&segments] (Node &current) {
     491                 :             :       if (current.is_root ())
     492                 :             :         return KeepGoing::No;
     493                 :             : 
     494                 :             :       auto children = current.parent.value ().children;
     495                 :             :       const Link *outer_link = nullptr;
     496                 :             : 
     497                 :             :       for (auto &kv : children)
     498                 :             :         {
     499                 :             :           auto &link = kv.first;
     500                 :             :           auto &child = kv.second;
     501                 :             : 
     502                 :             :           if (link.id == child.id)
     503                 :             :             {
     504                 :             :               outer_link = &link;
     505                 :             :               break;
     506                 :             :             }
     507                 :             :         }
     508                 :             : 
     509                 :             :       rust_assert (outer_link);
     510                 :             : 
     511                 :             :       outer_link->path.map ([&segments, outer_link] (Identifier path) {
     512                 :             :         segments.emplace (segments.begin (),
     513                 :             :                           Resolver::CanonicalPath::new_seg (outer_link->id,
     514                 :             :                                                             path.as_string ()));
     515                 :             :       });
     516                 :             : 
     517                 :             :       return KeepGoing::Yes;
     518                 :             :     });
     519                 :             : 
     520                 :             :     auto path = Resolver::CanonicalPath::create_empty ();
     521                 :             :     for (const auto &segment : segments)
     522                 :             :       path = path.append (segment);
     523                 :             : 
     524                 :             :     // Finally, append the name
     525                 :             :     path = path.append (Resolver::CanonicalPath::new_seg (id, name));
     526                 :             : 
     527                 :             :     return path;
     528                 :             :   });
     529                 :             : }
     530                 :             : 
     531                 :             : template <Namespace N>
     532                 :             : tl::optional<Rib &>
     533                 :             : ForeverStack<N>::dfs_rib (ForeverStack<N>::Node &starting_point, NodeId to_find)
     534                 :             : {
     535                 :             :   if (starting_point.id == to_find)
     536                 :             :     return starting_point.rib;
     537                 :             : 
     538                 :             :   for (auto &child : starting_point.children)
     539                 :             :     {
     540                 :             :       auto candidate = dfs_rib (child.second, to_find);
     541                 :             : 
     542                 :             :       if (candidate.has_value ())
     543                 :             :         return candidate;
     544                 :             :     }
     545                 :             : 
     546                 :             :   return tl::nullopt;
     547                 :             : }
     548                 :             : 
     549                 :             : template <Namespace N>
     550                 :             : tl::optional<Rib &>
     551                 :             : ForeverStack<N>::to_rib (NodeId rib_id)
     552                 :             : {
     553                 :             :   return dfs_rib (root, rib_id);
     554                 :             : }
     555                 :             : 
     556                 :             : template <Namespace N>
     557                 :             : void
     558                 :             : ForeverStack<N>::stream_rib (std::stringstream &stream, const Rib &rib,
     559                 :             :                              const std::string &next,
     560                 :             :                              const std::string &next_next)
     561                 :             : {
     562                 :             :   if (rib.get_values ().empty ())
     563                 :             :     {
     564                 :             :       stream << next << "rib: {},\n";
     565                 :             :       return;
     566                 :             :     }
     567                 :             : 
     568                 :             :   stream << next << "rib: {\n";
     569                 :             : 
     570                 :             :   for (const auto &kv : rib.get_values ())
     571                 :             :     stream << next_next << kv.first << ": " << kv.second << "\n";
     572                 :             : 
     573                 :             :   stream << next << "},\n";
     574                 :             : }
     575                 :             : 
     576                 :             : template <Namespace N>
     577                 :             : void
     578                 :             : ForeverStack<N>::stream_node (std::stringstream &stream, unsigned indentation,
     579                 :             :                               const ForeverStack<N>::Node &node)
     580                 :             : {
     581                 :             :   auto indent = std::string (indentation, ' ');
     582                 :             :   auto next = std::string (indentation + 4, ' ');
     583                 :             :   auto next_next = std::string (indentation + 8, ' ');
     584                 :             : 
     585                 :             :   stream << indent << "Node {\n"
     586                 :             :          << next << "is_root: " << (node.is_root () ? "true" : "false") << ",\n"
     587                 :             :          << next << "is_leaf: " << (node.is_leaf () ? "true" : "false")
     588                 :             :          << ",\n";
     589                 :             : 
     590                 :             :   stream_rib (stream, node.rib, next, next_next);
     591                 :             : 
     592                 :             :   stream << indent << "}\n";
     593                 :             : 
     594                 :             :   for (auto &kv : node.children)
     595                 :             :     {
     596                 :             :       auto link = kv.first;
     597                 :             :       auto child = kv.second;
     598                 :             :       stream << indent << "Link (" << link.id << ", "
     599                 :             :              << (link.path.has_value () ? link.path.value ().as_string ()
     600                 :             :                                         : "<anon>")
     601                 :             :              << "):\n";
     602                 :             : 
     603                 :             :       stream_node (stream, indentation + 4, child);
     604                 :             : 
     605                 :             :       stream << '\n';
     606                 :             :     }
     607                 :             : }
     608                 :             : 
     609                 :             : template <Namespace N>
     610                 :             : std::string
     611                 :             : ForeverStack<N>::as_debug_string ()
     612                 :             : {
     613                 :             :   std::stringstream stream;
     614                 :             : 
     615                 :             :   stream_node (stream, 0, root);
     616                 :             : 
     617                 :             :   return stream.str ();
     618                 :             : }
     619                 :             : 
     620                 :             : // FIXME: Can we add selftests?
     621                 :             : 
     622                 :             : } // namespace Resolver2_0
     623                 :             : } // namespace Rust
        

Generated by: LCOV version 2.1-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.