LCOV - code coverage report
Current view: top level - gcc/rust/resolve - rust-name-resolution-context.hxx (source / functions) Coverage Total Hit
Test: gcc.info Lines: 83.6 % 110 92
Test Date: 2026-06-20 15:32:29 Functions: 50.0 % 12 6
Legend: Lines:     hit not hit

            Line data    Source code
       1              : // Copyright (C) 2026 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 "optional.h"
      20              : #include "rust-name-resolution-context.h"
      21              : 
      22              : /**
      23              :  * Split the actual path resolution logic in its own file because it's a lot,
      24              :  * and it could get even worse for certain edge cases.
      25              :  */
      26              : 
      27              : namespace Rust {
      28              : namespace Resolver2_0 {
      29              : 
      30              : template <Namespace N>
      31              : tl::optional<Rib::Definition>
      32        91825 : NameResolutionContext::resolve_path (
      33              :   ForeverStack<N> &stack, const ResolutionPath &path, ResolutionMode mode,
      34              :   std::function<void (Usage, Definition)> insert_segment_resolution,
      35              :   std::vector<Error> &collect_errors)
      36              : {
      37        91825 :   std::reference_wrapper<typename ForeverStack<N>::Node> starting_point
      38              :     = stack.cursor ();
      39              : 
      40        91825 :   return NameResolutionContext::resolve_path (stack, path, mode,
      41              :                                               insert_segment_resolution,
      42        91825 :                                               collect_errors, starting_point);
      43              : }
      44              : 
      45              : template <Namespace N>
      46              : tl::optional<Rib::Definition>
      47            0 : NameResolutionContext::resolve_path (
      48              :   ForeverStack<N> &stack, const ResolutionPath &path, ResolutionMode mode,
      49              :   std::function<void (Usage, Definition)> insert_segment_resolution,
      50              :   std::vector<Error> &collect_errors, NodeId starting_point_id)
      51              : 
      52              : {
      53            0 :   auto starting_point = stack.dfs_node (stack.root, starting_point_id);
      54              : 
      55              :   // We may have a prelude, but haven't visited it yet and thus it's not in
      56              :   // our nodes
      57            0 :   if (!starting_point)
      58            0 :     return tl::nullopt;
      59              : 
      60            0 :   return NameResolutionContext::resolve_path (stack, path, mode,
      61              :                                               insert_segment_resolution,
      62            0 :                                               collect_errors, *starting_point);
      63              : }
      64              : 
      65              : template <Namespace N>
      66              : tl::optional<Rib::Definition>
      67        91825 : NameResolutionContext::resolve_path (
      68              :   ForeverStack<N> &stack, const ResolutionPath &path, ResolutionMode mode,
      69              :   std::function<void (Usage, Definition)> insert_segment_resolution,
      70              :   std::vector<Error> &collect_errors,
      71              :   std::reference_wrapper<typename ForeverStack<N>::Node> starting_point)
      72              : {
      73        91825 :   bool can_descend = true;
      74              : 
      75        91825 :   rust_debug ("resolving %s", path.as_string ().c_str ());
      76              : 
      77        91825 :   if (auto lang_item = path.get_lang_prefix ())
      78              :     {
      79              :       NodeId seg_id
      80          392 :         = Analysis::Mappings::get ().get_lang_item_node (lang_item->first);
      81              : 
      82          392 :       insert_segment_resolution (Usage (lang_item->second),
      83          392 :                                  Definition (seg_id));
      84              : 
      85          392 :       if (path.get_segments ().empty ())
      86          392 :         return Rib::Definition::NonShadowable (seg_id);
      87              : 
      88            0 :       auto new_start = stack.dfs_node (stack.root, seg_id);
      89            0 :       rust_assert (new_start.has_value ());
      90            0 :       starting_point = new_start.value ();
      91              : 
      92            0 :       can_descend = false;
      93              :     }
      94              :   else
      95              :     {
      96        91433 :       switch (mode)
      97              :         {
      98              :         case ResolutionMode::Normal:
      99              :           break; // default
     100          951 :         case ResolutionMode::FromRoot:
     101          951 :           starting_point = stack.root;
     102          951 :           break;
     103            0 :         case ResolutionMode::FromExtern:
     104            0 :           starting_point = stack.extern_prelude;
     105            0 :           break;
     106            0 :         default:
     107            0 :           rust_unreachable ();
     108              :         }
     109              :     }
     110              : 
     111        91433 :   if (path.get_segments ().empty ())
     112            1 :     return Rib::Definition::NonShadowable (starting_point.get ().id);
     113              : 
     114        91432 :   auto &segments = path.get_segments ();
     115              : 
     116              :   // if there's only one segment, we just use `get`
     117       182864 :   if (can_descend && segments.size () == 1)
     118              :     {
     119        71621 :       auto &seg = segments.front ();
     120              : 
     121        71621 :       tl::optional<Rib::Definition> res
     122       286484 :         = stack.get (starting_point.get (), seg.name);
     123              : 
     124        71621 :       if (!res)
     125        52337 :         res = stack.get_lang_prelude (seg.name);
     126              : 
     127        54535 :       if (N == Namespace::Types && !res)
     128              :         {
     129          200 :           if (seg.is_crate_path_seg ())
     130              :             {
     131           53 :               insert_segment_resolution (Usage (seg.node_id),
     132           53 :                                          Definition (stack.root.id));
     133              :               // TODO: does NonShadowable matter?
     134           53 :               return Rib::Definition::NonShadowable (stack.root.id);
     135              :             }
     136          147 :           else if (seg.is_lower_self_seg ())
     137              :             {
     138            5 :               NodeId id = stack.find_closest_module (starting_point.get ()).id;
     139            5 :               insert_segment_resolution (Usage (seg.node_id), Definition (id));
     140              :               // TODO: does NonShadowable matter?
     141            5 :               return Rib::Definition::NonShadowable (id);
     142              :             }
     143          142 :           else if (seg.is_super_path_seg ())
     144              :             {
     145              :               auto &closest_module
     146            1 :                 = stack.find_closest_module (starting_point.get ());
     147            1 :               if (closest_module.is_root ())
     148              :                 {
     149            0 :                   rust_error_at (seg.locus, ErrorCode::E0433,
     150              :                                  "too many leading %<super%> keywords");
     151            0 :                   return tl::nullopt;
     152              :                 }
     153              : 
     154            1 :               NodeId id
     155            1 :                 = stack.find_closest_module (closest_module.parent.value ()).id;
     156            1 :               insert_segment_resolution (Usage (seg.node_id), Definition (id));
     157              :               // TODO: does NonShadowable matter?
     158            1 :               return Rib::Definition::NonShadowable (id);
     159              :             }
     160              :           else
     161              :             {
     162              :               // HACK: check for a module after we check the language prelude
     163          628 :               for (auto &kv :
     164          141 :                    stack.find_closest_module (starting_point.get ()).children)
     165              :                 {
     166          496 :                   auto &link = kv.first;
     167              : 
     168          992 :                   if (link.path.map_or (
     169         1418 :                         [&seg] (Identifier path) {
     170          426 :                           auto &path_str = path.as_string ();
     171          426 :                           return path_str == seg.name;
     172              :                         },
     173          496 :                         false))
     174              :                     {
     175            9 :                       insert_segment_resolution (Usage (seg.node_id),
     176            9 :                                                  Definition (kv.second.id));
     177            9 :                       return Rib::Definition::NonShadowable (kv.second.id);
     178              :                     }
     179              :                 }
     180              :             }
     181              :         }
     182              : 
     183        71553 :       if (res && !res->is_ambiguous ())
     184        70957 :         insert_segment_resolution (Usage (seg.node_id),
     185        70957 :                                    Definition (res->get_node_id ()));
     186        71553 :       return res;
     187        71621 :     }
     188              : 
     189        19811 :   auto iterator = segments.begin ();
     190        19811 :   if (can_descend)
     191              :     {
     192        19811 :       if (auto res = stack.find_starting_point (segments, starting_point,
     193              :                                                 insert_segment_resolution,
     194              :                                                 collect_errors))
     195        19809 :         iterator = *res;
     196              :       else
     197            2 :         return tl::nullopt;
     198              :     }
     199              : 
     200              :   // We do the first part of path resolution exclusively in the types NS - this
     201              :   // gives us a node in which to resolve the last segment of the path.
     202              : 
     203              :   // We take our starting point and then get the equivalent Node from the Types
     204              :   // NS - since it existed in whatever namespace we are right now, we assume it
     205              :   // exists in the types NS.
     206              :   auto types_starting_point
     207        19809 :     = types.dfs_node (types.root, starting_point.get ().id);
     208              : 
     209              :   // TODO: Add a method for converting a node between namespaces? Make all of
     210              :   // the starting point stuff return a NodeId rather than a Node&? And take a
     211              :   // NodeId as a starting point rather than a Node?
     212              : 
     213              :   auto node
     214        19809 :     = types.resolve_segments (types_starting_point.value (), segments, iterator,
     215              :                               insert_segment_resolution, collect_errors);
     216              : 
     217        19809 :   if (!node)
     218         1846 :     return tl::nullopt;
     219              : 
     220              :   // This node now represents the Node which *should* contain the definition
     221              :   // used by the last segment. We now get the equivalent Node from this
     222              :   // namespace after finding it in the types NS.
     223        17963 :   auto final_node_id = node.value ().id;
     224        17963 :   auto final_node = stack.dfs_node (stack.root, final_node_id).value ();
     225              : 
     226              :   // leave resolution within impl blocks to type checker
     227        17963 :   if (final_node.rib.kind == Rib::Kind::TraitOrImpl)
     228            0 :     return tl::nullopt;
     229              : 
     230        17963 :   auto &seg = segments.back ();
     231        22662 :   std::string seg_name = seg.name;
     232              : 
     233        17963 :   tl::optional<Rib::Definition> res
     234              :     = stack.resolve_final_segment (final_node, seg_name,
     235        17963 :                                    seg.is_lower_self_seg ());
     236              :   // Ok we didn't find it in the rib, Lets try the prelude...
     237        17963 :   if (!res)
     238         7722 :     res = stack.get_lang_prelude (seg_name);
     239              : 
     240         4699 :   if (N == Namespace::Types && !res)
     241              :     {
     242              :       // HACK: check for a module after we check the language prelude
     243         2339 :       for (auto &kv : final_node.children)
     244              :         {
     245         1338 :           auto &link = kv.first;
     246              : 
     247         2676 :           if (link.path.map_or (
     248         2770 :                 [&seg_name] (Identifier path) {
     249           94 :                   auto &path_str = path.as_string ();
     250           94 :                   return path_str == seg_name;
     251              :                 },
     252         1338 :                 false))
     253              :             {
     254           59 :               insert_segment_resolution (Usage (seg.node_id),
     255           59 :                                          Definition (kv.second.id));
     256           59 :               return Rib::Definition::NonShadowable (kv.second.id);
     257              :             }
     258              :         }
     259              :     }
     260              : 
     261        17904 :   if (res && !res->is_ambiguous ())
     262        10239 :     insert_segment_resolution (Usage (seg.node_id),
     263        10239 :                                Definition (res->get_node_id ()));
     264              : 
     265        17904 :   return res;
     266        17963 : }
     267              : 
     268              : } // namespace Resolver2_0
     269              : } // namespace Rust
        

Generated by: LCOV version 2.4-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.