LCOV - code coverage report
Current view: top level - gcc/rust/ast - rust-item.h (source / functions) Coverage Total Hit
Test: gcc.info Lines: 95.0 % 958 910
Test Date: 2026-10-24 16:24:59 Functions: 93.3 % 253 236
Legend: Lines:     hit not hit

            Line data    Source code
       1              : // Copyright (C) 2020-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              : #ifndef RUST_AST_ITEM_H
      20              : #define RUST_AST_ITEM_H
      21              : 
      22              : #include "rust-ast.h"
      23              : #include "rust-hir-map.h"
      24              : #include "rust-mapping-common.h"
      25              : #include "rust-path.h"
      26              : #include "rust-common.h"
      27              : #include "rust-expr.h"
      28              : 
      29              : namespace Rust {
      30              : namespace AST {
      31              : // forward decls
      32              : class TypePath;
      33              : 
      34              : // TODO: inline?
      35              : /*struct AbiName {
      36              :     std::string abi_name;
      37              :     // Technically is meant to be STRING_LITERAL
      38              : 
      39              :   public:
      40              :     // Returns whether abi name is empty, i.e. doesn't exist.
      41              :     bool is_empty() const {
      42              :         return abi_name.empty();
      43              :     }
      44              : 
      45              :     AbiName(std::string name) : abi_name(std::move(name)) {}
      46              : 
      47              :     // Empty AbiName constructor
      48              :     AbiName() {}
      49              : };*/
      50              : 
      51              : // A type generic parameter (as opposed to a lifetime generic parameter)
      52              : class TypeParam : public GenericParam
      53              : {
      54              :   AST::AttrVec outer_attrs;
      55              :   Identifier type_representation;
      56              :   std::vector<std::unique_ptr<TypeParamBound>> type_param_bounds;
      57              :   std::unique_ptr<Type> type;
      58              :   location_t locus;
      59              :   bool was_impl_trait;
      60              : 
      61              : public:
      62       330483 :   Identifier get_type_representation () const { return type_representation; }
      63              : 
      64              :   // Returns whether the type of the type param has been specified.
      65      2270675 :   bool has_type () const { return type != nullptr; }
      66              : 
      67              :   // Returns whether the type param has type param bounds.
      68        23879 :   bool has_type_param_bounds () const { return !type_param_bounds.empty (); }
      69              : 
      70              :   // Returns whether the type param has an outer attribute.
      71            0 :   bool has_outer_attribute () const { return !outer_attrs.empty (); }
      72              : 
      73      1684682 :   AST::AttrVec &get_outer_attrs () { return outer_attrs; }
      74              : 
      75        19142 :   TypeParam (Identifier type_representation, location_t locus = UNDEF_LOCATION,
      76              :              std::vector<std::unique_ptr<TypeParamBound>> type_param_bounds
      77              :              = std::vector<std::unique_ptr<TypeParamBound>> (),
      78              :              std::unique_ptr<Type> type = nullptr,
      79              :              AST::AttrVec outer_attrs = {}, bool was_impl_trait = false)
      80        19142 :     : GenericParam (Analysis::Mappings::get ().get_next_node_id ()),
      81        19142 :       outer_attrs (std::move (outer_attrs)),
      82        19142 :       type_representation (std::move (type_representation)),
      83        19142 :       type_param_bounds (std::move (type_param_bounds)),
      84        19142 :       type (std::move (type)), locus (locus), was_impl_trait (was_impl_trait)
      85        19142 :   {}
      86              : 
      87              :   // Copy constructor uses clone
      88        64631 :   TypeParam (TypeParam const &other)
      89        64631 :     : GenericParam (other.node_id), outer_attrs (other.outer_attrs),
      90        64631 :       type_representation (other.type_representation), locus (other.locus),
      91       129262 :       was_impl_trait (other.was_impl_trait)
      92              :   {
      93              :     // guard to prevent null pointer dereference
      94        64631 :     if (other.type != nullptr)
      95         1236 :       type = other.type->clone_type ();
      96              : 
      97        64631 :     type_param_bounds.reserve (other.type_param_bounds.size ());
      98        79444 :     for (const auto &e : other.type_param_bounds)
      99        14813 :       type_param_bounds.push_back (e->clone_type_param_bound ());
     100        64631 :   }
     101              : 
     102              :   // Overloaded assignment operator to clone
     103              :   TypeParam &operator= (TypeParam const &other)
     104              :   {
     105              :     type_representation = other.type_representation;
     106              :     outer_attrs = other.outer_attrs;
     107              :     locus = other.locus;
     108              :     node_id = other.node_id;
     109              :     was_impl_trait = other.was_impl_trait;
     110              : 
     111              :     // guard to prevent null pointer dereference
     112              :     if (other.type != nullptr)
     113              :       type = other.type->clone_type ();
     114              :     else
     115              :       type = nullptr;
     116              : 
     117              :     type_param_bounds.reserve (other.type_param_bounds.size ());
     118              :     for (const auto &e : other.type_param_bounds)
     119              :       type_param_bounds.push_back (e->clone_type_param_bound ());
     120              : 
     121              :     return *this;
     122              :   }
     123              : 
     124              :   // move constructors
     125              :   TypeParam (TypeParam &&other) = default;
     126              :   TypeParam &operator= (TypeParam &&other) = default;
     127              : 
     128              :   std::string as_string () const override;
     129              : 
     130       330060 :   location_t get_locus () const override final { return locus; }
     131              : 
     132        14371 :   Kind get_kind () const override final { return Kind::Type; }
     133              : 
     134              :   void accept_vis (ASTVisitor &vis) override;
     135              : 
     136              :   // TODO: is this better? Or is a "vis_block" better?
     137        14728 :   Type &get_type ()
     138              :   {
     139        14728 :     rust_assert (type != nullptr);
     140        14728 :     return *type;
     141              :   }
     142              : 
     143         4587 :   std::unique_ptr<Type> &get_type_ptr ()
     144              :   {
     145         4587 :     rust_assert (type != nullptr);
     146         4587 :     return type;
     147              :   }
     148              : 
     149         1055 :   std::vector<std::unique_ptr<TypeParamBound>> &get_type_param_bounds ()
     150              :   {
     151      1923177 :     return type_param_bounds;
     152              :   }
     153              : 
     154              :   const std::vector<std::unique_ptr<TypeParamBound>> &
     155              :   get_type_param_bounds () const
     156              :   {
     157              :     return type_param_bounds;
     158              :   }
     159              : 
     160        18975 :   bool from_impl_trait () const { return was_impl_trait; }
     161              : 
     162              : protected:
     163              :   // Clone function implementation as virtual method
     164        54202 :   TypeParam *clone_generic_param_impl () const override
     165              :   {
     166        54202 :     return new TypeParam (*this);
     167              :   }
     168              : };
     169              : 
     170              : /* "where" clause item base. Abstract - use LifetimeWhereClauseItem,
     171              :  * TypeBoundWhereClauseItem */
     172         7536 : class WhereClauseItem
     173              : {
     174              : public:
     175              :   virtual ~WhereClauseItem () {}
     176              : 
     177              :   // Unique pointer custom clone function
     178         5846 :   std::unique_ptr<WhereClauseItem> clone_where_clause_item () const
     179              :   {
     180         5846 :     return std::unique_ptr<WhereClauseItem> (clone_where_clause_item_impl ());
     181              :   }
     182              : 
     183              :   virtual std::string as_string () const = 0;
     184              : 
     185              :   virtual void accept_vis (ASTVisitor &vis) = 0;
     186              : 
     187              :   virtual NodeId get_node_id () const = 0;
     188              : 
     189              : protected:
     190              :   // Clone function implementation as pure virtual method
     191              :   virtual WhereClauseItem *clone_where_clause_item_impl () const = 0;
     192              : };
     193              : 
     194              : // A lifetime where clause item
     195              : class LifetimeWhereClauseItem : public WhereClauseItem
     196              : {
     197              :   Lifetime lifetime;
     198              :   std::vector<Lifetime> lifetime_bounds;
     199              :   location_t locus;
     200              :   NodeId node_id;
     201              : 
     202              : public:
     203            3 :   LifetimeWhereClauseItem (Lifetime lifetime,
     204              :                            std::vector<Lifetime> lifetime_bounds,
     205              :                            location_t locus)
     206            3 :     : lifetime (std::move (lifetime)),
     207            3 :       lifetime_bounds (std::move (lifetime_bounds)), locus (locus),
     208            3 :       node_id (Analysis::Mappings::get ().get_next_node_id ())
     209            3 :   {}
     210              : 
     211              :   std::string as_string () const override;
     212              : 
     213              :   void accept_vis (ASTVisitor &vis) override;
     214              : 
     215            3 :   NodeId get_node_id () const override final { return node_id; }
     216              : 
     217          259 :   Lifetime &get_lifetime () { return lifetime; }
     218              : 
     219          259 :   std::vector<Lifetime> &get_lifetime_bounds () { return lifetime_bounds; }
     220              : 
     221            3 :   location_t get_locus () const { return locus; }
     222              : 
     223              : protected:
     224              :   // Clone function implementation as (not pure) virtual method
     225            4 :   LifetimeWhereClauseItem *clone_where_clause_item_impl () const override
     226              :   {
     227            4 :     return new LifetimeWhereClauseItem (*this);
     228              :   }
     229              : };
     230              : 
     231              : // A type bound where clause item
     232              : class TypeBoundWhereClauseItem : public WhereClauseItem
     233              : {
     234              :   std::vector<LifetimeParam> for_lifetimes;
     235              :   std::unique_ptr<Type> bound_type;
     236              :   std::vector<std::unique_ptr<TypeParamBound>> type_param_bounds;
     237              :   NodeId node_id;
     238              :   location_t locus;
     239              : 
     240              : public:
     241              :   // Returns whether the item has ForLifetimes
     242          345 :   bool has_for_lifetimes () const { return !for_lifetimes.empty (); }
     243              : 
     244       232795 :   std::vector<LifetimeParam> &get_for_lifetimes () { return for_lifetimes; }
     245              : 
     246              :   // Returns whether the item has type param bounds
     247              :   bool has_type_param_bounds () const { return !type_param_bounds.empty (); }
     248              : 
     249         1691 :   TypeBoundWhereClauseItem (
     250              :     std::vector<LifetimeParam> for_lifetimes, std::unique_ptr<Type> bound_type,
     251              :     std::vector<std::unique_ptr<TypeParamBound>> type_param_bounds,
     252              :     location_t locus)
     253         1691 :     : for_lifetimes (std::move (for_lifetimes)),
     254         1691 :       bound_type (std::move (bound_type)),
     255         1691 :       type_param_bounds (std::move (type_param_bounds)),
     256         1691 :       node_id (Analysis::Mappings::get ().get_next_node_id ()), locus (locus)
     257         1691 :   {}
     258              : 
     259              :   // Copy constructor requires clone
     260         5842 :   TypeBoundWhereClauseItem (TypeBoundWhereClauseItem const &other)
     261         5842 :     : for_lifetimes (other.for_lifetimes),
     262         5842 :       bound_type (other.bound_type->clone_type ())
     263              :   {
     264         5842 :     node_id = other.node_id;
     265         5842 :     type_param_bounds.reserve (other.type_param_bounds.size ());
     266        11952 :     for (const auto &e : other.type_param_bounds)
     267         6110 :       type_param_bounds.push_back (e->clone_type_param_bound ());
     268         5842 :   }
     269              : 
     270              :   // Overload assignment operator to clone
     271              :   TypeBoundWhereClauseItem &operator= (TypeBoundWhereClauseItem const &other)
     272              :   {
     273              :     node_id = other.node_id;
     274              :     for_lifetimes = other.for_lifetimes;
     275              :     bound_type = other.bound_type->clone_type ();
     276              :     type_param_bounds.reserve (other.type_param_bounds.size ());
     277              :     for (const auto &e : other.type_param_bounds)
     278              :       type_param_bounds.push_back (e->clone_type_param_bound ());
     279              : 
     280              :     return *this;
     281              :   }
     282              : 
     283              :   // move constructors
     284              :   TypeBoundWhereClauseItem (TypeBoundWhereClauseItem &&other) = default;
     285              :   TypeBoundWhereClauseItem &operator= (TypeBoundWhereClauseItem &&other)
     286              :     = default;
     287              : 
     288              :   std::string as_string () const override;
     289              : 
     290              :   void accept_vis (ASTVisitor &vis) override;
     291              : 
     292       254219 :   Type &get_type ()
     293              :   {
     294       254219 :     rust_assert (bound_type != nullptr);
     295       254219 :     return *bound_type;
     296              :   }
     297              : 
     298        79482 :   std::unique_ptr<Type> &get_type_ptr ()
     299              :   {
     300        79482 :     rust_assert (bound_type != nullptr);
     301        79482 :     return bound_type;
     302              :   }
     303              : 
     304              :   // TODO: this mutable getter seems really dodgy. Think up better way.
     305          345 :   std::vector<std::unique_ptr<TypeParamBound>> &get_type_param_bounds ()
     306              :   {
     307       272043 :     return type_param_bounds;
     308              :   }
     309              : 
     310              :   const std::vector<std::unique_ptr<TypeParamBound>> &
     311              :   get_type_param_bounds () const
     312              :   {
     313              :     return type_param_bounds;
     314              :   }
     315              : 
     316         1684 :   NodeId get_node_id () const override final { return node_id; }
     317              : 
     318         1684 :   location_t get_locus () const { return locus; }
     319              : 
     320              : protected:
     321              :   // Clone function implementation as (not pure) virtual method
     322         5842 :   TypeBoundWhereClauseItem *clone_where_clause_item_impl () const override
     323              :   {
     324         5842 :     return new TypeBoundWhereClauseItem (*this);
     325              :   }
     326              : };
     327              : 
     328              : // A where clause
     329       130487 : class WhereClause
     330              : {
     331              :   std::vector<std::unique_ptr<WhereClauseItem>> where_clause_items;
     332              :   NodeId node_id;
     333              : 
     334              : public:
     335        65491 :   WhereClause (std::vector<std::unique_ptr<WhereClauseItem>> where_clause_items)
     336        65491 :     : where_clause_items (std::move (where_clause_items)),
     337        65491 :       node_id (Analysis::Mappings::get ().get_next_node_id ())
     338        65491 :   {}
     339              : 
     340              :   // copy constructor with vector clone
     341       238823 :   WhereClause (WhereClause const &other)
     342       238823 :   {
     343       238823 :     node_id = other.node_id;
     344       238823 :     where_clause_items.reserve (other.where_clause_items.size ());
     345       244669 :     for (const auto &e : other.where_clause_items)
     346         5846 :       where_clause_items.push_back (e->clone_where_clause_item ());
     347       238823 :   }
     348              : 
     349              :   // overloaded assignment operator with vector clone
     350            0 :   WhereClause &operator= (WhereClause const &other)
     351              :   {
     352            0 :     node_id = other.node_id;
     353            0 :     where_clause_items.reserve (other.where_clause_items.size ());
     354            0 :     for (const auto &e : other.where_clause_items)
     355            0 :       where_clause_items.push_back (e->clone_where_clause_item ());
     356              : 
     357            0 :     return *this;
     358              :   }
     359              : 
     360              :   // move constructors
     361        67261 :   WhereClause (WhereClause &&other) = default;
     362              :   WhereClause &operator= (WhereClause &&other) = default;
     363              : 
     364              :   // Creates a WhereClause with no items.
     365        64181 :   static WhereClause create_empty ()
     366              :   {
     367        64181 :     return WhereClause (std::vector<std::unique_ptr<WhereClauseItem>> ());
     368              :   }
     369              : 
     370              :   // Returns whether the WhereClause has no items.
     371      6277859 :   bool is_empty () const { return where_clause_items.empty (); }
     372              : 
     373              :   std::string as_string () const;
     374              : 
     375              :   NodeId get_node_id () const { return node_id; }
     376              : 
     377              :   // TODO: this mutable getter seems kinda dodgy
     378          346 :   std::vector<std::unique_ptr<WhereClauseItem>> &get_items ()
     379              :   {
     380       253797 :     return where_clause_items;
     381              :   }
     382              :   const std::vector<std::unique_ptr<WhereClauseItem>> &get_items () const
     383              :   {
     384              :     return where_clause_items;
     385              :   }
     386              : };
     387              : 
     388              : // Abstract class Param
     389        55766 : class Param : public Visitable
     390              : {
     391              : public:
     392       271106 :   Param (std::vector<Attribute> outer_attrs, location_t locus)
     393       271106 :     : outer_attrs (std::move (outer_attrs)), locus (locus),
     394       271106 :       node_id (Analysis::Mappings::get ().get_next_node_id ())
     395       271106 :   {}
     396              : 
     397              :   virtual ~Param () = default;
     398              : 
     399       187122 :   std::unique_ptr<Param> clone_param () const
     400              :   {
     401       187122 :     return std::unique_ptr<Param> (clone_param_impl ());
     402              :   }
     403              : 
     404       980450 :   virtual bool is_variadic () const { return false; }
     405              : 
     406       909029 :   virtual bool is_self () const { return false; }
     407              : 
     408        28244 :   NodeId get_node_id () const { return node_id; }
     409              : 
     410        42222 :   location_t get_locus () const { return locus; }
     411              : 
     412       102015 :   std::vector<Attribute> get_outer_attrs () const { return outer_attrs; }
     413              : 
     414      1964194 :   std::vector<Attribute> &get_outer_attrs () { return outer_attrs; }
     415              : 
     416              :   virtual Param *clone_param_impl () const = 0;
     417              : 
     418              :   virtual std::string as_string () const = 0;
     419              : 
     420              : protected:
     421              :   std::vector<Attribute> outer_attrs;
     422              :   location_t locus;
     423              :   NodeId node_id;
     424              : };
     425              : 
     426              : // A self parameter in a method
     427              : class SelfParam : public Param
     428              : {
     429              :   bool has_ref;
     430              :   bool is_mut;
     431              :   // bool has_lifetime; // only possible if also ref
     432              :   tl::optional<Lifetime> lifetime;
     433              : 
     434              :   // bool has_type; // only possible if not ref
     435              :   std::unique_ptr<Type> type;
     436              : 
     437              :   // Unrestricted constructor used for error state
     438              :   SelfParam (tl::optional<Lifetime> lifetime, bool has_ref, bool is_mut,
     439              :              Type *type)
     440              :     : Param ({}, UNDEF_LOCATION), has_ref (has_ref), is_mut (is_mut),
     441              :       lifetime (std::move (lifetime)), type (type)
     442              :   {}
     443              :   // this is ok as no outside classes can ever call this
     444              : 
     445              :   // TODO: self param can have outer attributes
     446              : 
     447              : public:
     448              :   // Returns whether the self-param has a type field.
     449      2897144 :   bool has_type () const { return type != nullptr; }
     450              : 
     451              :   // Returns whether the self-param has a valid lifetime.
     452      1980357 :   bool has_lifetime () const { return lifetime.has_value (); }
     453              : 
     454              :   // Returns whether the self-param is in an error state.
     455            0 :   bool is_error () const
     456              :   {
     457            0 :     return (has_type () && has_lifetime ()) || (has_lifetime () && !has_ref);
     458              :     // not having either is not an error
     459              :   }
     460              : 
     461              :   // Creates an error state self-param.
     462              :   static SelfParam create_error ()
     463              :   {
     464              :     // cannot have no ref but have a lifetime at the same time
     465              :     return SelfParam (Lifetime (Lifetime::STATIC), false, false, nullptr);
     466              :   }
     467              : 
     468              :   // Type-based self parameter (not ref, no lifetime)
     469         7883 :   SelfParam (std::unique_ptr<Type> type, bool is_mut, location_t locus)
     470         7883 :     : Param ({}, locus), has_ref (false), is_mut (is_mut),
     471         7883 :       lifetime (tl::nullopt), type (std::move (type))
     472         7883 :   {}
     473              : 
     474              :   // Lifetime-based self parameter (is ref, no type)
     475        11046 :   SelfParam (tl::optional<Lifetime> lifetime, bool is_mut, location_t locus)
     476        11046 :     : Param ({}, locus), has_ref (true), is_mut (is_mut),
     477        11046 :       lifetime (std::move (lifetime))
     478        11046 :   {}
     479              : 
     480              :   // Copy constructor requires clone
     481        99315 :   SelfParam (SelfParam const &other)
     482        99315 :     : Param (other.get_outer_attrs (), other.get_locus ()),
     483       198630 :       has_ref (other.has_ref), is_mut (other.is_mut), lifetime (other.lifetime)
     484              :   {
     485        99315 :     node_id = other.node_id;
     486        99315 :     if (other.type != nullptr)
     487           98 :       type = other.type->clone_type ();
     488        99315 :   }
     489              : 
     490              :   // Overload assignment operator to use clone
     491              :   SelfParam &operator= (SelfParam const &other)
     492              :   {
     493              :     is_mut = other.is_mut;
     494              :     has_ref = other.has_ref;
     495              :     lifetime = other.lifetime;
     496              :     locus = other.locus;
     497              :     node_id = other.node_id;
     498              :     outer_attrs = other.outer_attrs;
     499              : 
     500              :     if (other.type != nullptr)
     501              :       type = other.type->clone_type ();
     502              :     else
     503              :       type = nullptr;
     504              : 
     505              :     return *this;
     506              :   }
     507              : 
     508              :   // move constructors
     509              :   SelfParam (SelfParam &&other) = default;
     510              :   SelfParam &operator= (SelfParam &&other) = default;
     511              : 
     512              :   std::string as_string () const override;
     513              : 
     514       136902 :   location_t get_locus () const { return locus; }
     515              : 
     516       716787 :   bool is_self () const override { return true; }
     517              : 
     518        27512 :   bool get_has_ref () const { return has_ref; };
     519        23969 :   bool get_is_mut () const { return is_mut; }
     520              : 
     521            0 :   Lifetime get_lifetime () const { return lifetime.value (); }
     522       942107 :   Lifetime &get_lifetime () { return lifetime.value (); }
     523              : 
     524        37587 :   NodeId get_node_id () const { return node_id; }
     525              : 
     526              :   // TODO: is this better? Or is a "vis_block" better?
     527         3933 :   Type &get_type ()
     528              :   {
     529         3933 :     rust_assert (has_type ());
     530         3933 :     return *type;
     531              :   }
     532              : 
     533         1046 :   std::unique_ptr<Type> &get_type_ptr ()
     534              :   {
     535         1046 :     rust_assert (has_type ());
     536         1046 :     return type;
     537              :   }
     538              : 
     539              :   void accept_vis (ASTVisitor &vis) override;
     540              : 
     541        80536 :   SelfParam *clone_param_impl () const override
     542              :   {
     543        80536 :     return new SelfParam (*this);
     544              :   }
     545              : };
     546              : 
     547              : // Qualifiers for function, i.e. const, unsafe, extern etc.
     548       131040 : class FunctionQualifiers
     549              : {
     550              :   Default default_status;
     551              :   Async async_status;
     552              :   Const const_status;
     553              :   Unsafety unsafe_status;
     554              :   bool has_extern;
     555              :   std::string extern_abi;
     556              :   location_t locus;
     557              : 
     558              : public:
     559        37674 :   FunctionQualifiers (location_t locus, Default default_status,
     560              :                       Async async_status, Const const_status,
     561              :                       Unsafety unsafe_status, bool has_extern = false,
     562              :                       std::string extern_abi = std::string ())
     563        37674 :     : default_status (default_status), async_status (async_status),
     564        37674 :       const_status (const_status), unsafe_status (unsafe_status),
     565        37674 :       has_extern (has_extern), extern_abi (std::move (extern_abi)),
     566        37674 :       locus (locus)
     567              :   {
     568        37674 :     if (!this->extern_abi.empty ())
     569              :       {
     570              :         // having extern is required; not having it is an implementation error
     571          756 :         rust_assert (has_extern);
     572              :       }
     573        37674 :   }
     574              : 
     575              :   std::string as_string () const;
     576              : 
     577        62920 :   bool is_default () const { return default_status == Default::Yes; }
     578        53056 :   bool is_unsafe () const { return unsafe_status == Unsafety::Unsafe; }
     579        51347 :   bool is_extern () const { return has_extern; }
     580        54642 :   bool is_const () const { return const_status == Const::Yes; }
     581        89684 :   bool is_async () const { return async_status == Async::Yes; }
     582         1470 :   std::string get_extern_abi () const { return extern_abi; }
     583        31824 :   bool has_abi () const { return !extern_abi.empty (); }
     584        31749 :   Const get_const_status () const { return const_status; }
     585        31749 :   Async get_async_status () const { return async_status; }
     586              : 
     587         1631 :   location_t get_locus () const { return locus; }
     588              : };
     589              : 
     590              : class VariadicParam : public Param
     591              : {
     592              :   std::unique_ptr<Pattern> param_name;
     593              : 
     594              : public:
     595           11 :   VariadicParam (std::unique_ptr<Pattern> param_name,
     596              :                  std::vector<Attribute> outer_attrs, location_t locus)
     597              :     : Param (std::move (outer_attrs), std::move (locus)),
     598           11 :       param_name (std::move (param_name))
     599           11 :   {}
     600              : 
     601          887 :   VariadicParam (std::vector<Attribute> outer_attrs, location_t locus)
     602          887 :     : Param (std::move (outer_attrs), std::move (locus)), param_name (nullptr)
     603          887 :   {}
     604              : 
     605         2700 :   VariadicParam (VariadicParam const &other)
     606         2700 :     : Param (other.get_outer_attrs (), other.locus)
     607              :   {
     608         2700 :     if (other.param_name != nullptr)
     609           33 :       param_name = other.param_name->clone_pattern ();
     610         2700 :   }
     611              : 
     612              :   VariadicParam &operator= (VariadicParam const &other)
     613              :   {
     614              :     outer_attrs = other.outer_attrs;
     615              :     locus = other.locus;
     616              :     node_id = other.node_id;
     617              :     if (other.param_name != nullptr)
     618              :       param_name = other.param_name->clone_pattern ();
     619              :     else
     620              :       param_name = nullptr;
     621              : 
     622              :     return *this;
     623              :   }
     624              : 
     625         5494 :   bool is_variadic () const override { return true; }
     626              : 
     627         1802 :   VariadicParam *clone_param_impl () const override
     628              :   {
     629         1802 :     return new VariadicParam (*this);
     630              :   }
     631              : 
     632          185 :   Pattern &get_pattern ()
     633              :   {
     634          185 :     rust_assert (param_name != nullptr);
     635          185 :     return *param_name;
     636              :   }
     637              : 
     638           55 :   std::unique_ptr<Pattern> &get_pattern_ptr ()
     639              :   {
     640           55 :     rust_assert (param_name != nullptr);
     641           55 :     return param_name;
     642              :   }
     643              : 
     644            0 :   const Pattern &get_pattern () const
     645              :   {
     646            0 :     rust_assert (param_name != nullptr);
     647            0 :     return *param_name;
     648              :   }
     649              : 
     650        20379 :   bool has_pattern () const { return param_name != nullptr; }
     651              : 
     652              :   void accept_vis (ASTVisitor &vis) override;
     653              : 
     654              :   std::string as_string () const override;
     655              : };
     656              : 
     657              : // A function parameter
     658              : class FunctionParam : public Param
     659              : {
     660              :   std::unique_ptr<Pattern> param_name;
     661              :   std::unique_ptr<Type> type;
     662              : 
     663              : public:
     664        28548 :   FunctionParam (std::unique_ptr<Pattern> param_name,
     665              :                  std::unique_ptr<Type> param_type,
     666              :                  std::vector<Attribute> outer_attrs, location_t locus)
     667              :     : Param (std::move (outer_attrs), locus),
     668        28548 :       param_name (std::move (param_name)), type (std::move (param_type))
     669        28548 :   {}
     670              : 
     671              :   // Copy constructor uses clone
     672       120716 :   FunctionParam (FunctionParam const &other)
     673       120716 :     : Param (other.get_outer_attrs (), other.locus)
     674              :   {
     675              :     // guard to prevent nullptr dereference
     676       120716 :     if (other.param_name != nullptr)
     677       120716 :       param_name = other.param_name->clone_pattern ();
     678       120716 :     if (other.type != nullptr)
     679       120716 :       type = other.type->clone_type ();
     680       120716 :   }
     681              : 
     682              :   // Overload assignment operator to use clone
     683              :   FunctionParam &operator= (FunctionParam const &other)
     684              :   {
     685              :     locus = other.locus;
     686              :     node_id = other.node_id;
     687              : 
     688              :     // guard to prevent nullptr dereference
     689              :     if (other.param_name != nullptr)
     690              :       param_name = other.param_name->clone_pattern ();
     691              :     else
     692              :       param_name = nullptr;
     693              :     if (other.type != nullptr)
     694              :       type = other.type->clone_type ();
     695              :     else
     696              :       type = nullptr;
     697              : 
     698              :     return *this;
     699              :   }
     700              : 
     701              :   // move constructors
     702        27883 :   FunctionParam (FunctionParam &&other) = default;
     703              :   FunctionParam &operator= (FunctionParam &&other) = default;
     704              : 
     705              :   // Returns whether FunctionParam is in an invalid state.
     706              :   bool is_error () const { return param_name == nullptr || type == nullptr; }
     707              : 
     708              :   // Creates an error FunctionParam.
     709              :   static FunctionParam create_error ()
     710              :   {
     711              :     return FunctionParam (nullptr, nullptr, {}, UNDEF_LOCATION);
     712              :   }
     713              : 
     714              :   std::string as_string () const override;
     715              : 
     716              :   // TODO: seems kinda dodgy. Think of better way.
     717      4060684 :   std::vector<Attribute> &get_outer_attrs () { return outer_attrs; }
     718       120716 :   const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
     719              : 
     720              :   // TODO: is this better? Or is a "vis_block" better?
     721      3536697 :   Pattern &get_pattern ()
     722              :   {
     723      3536697 :     rust_assert (param_name != nullptr);
     724      3536697 :     return *param_name;
     725              :   }
     726              : 
     727      1101354 :   std::unique_ptr<Pattern> &get_pattern_ptr ()
     728              :   {
     729      1101354 :     rust_assert (param_name != nullptr);
     730      1101354 :     return param_name;
     731              :   }
     732              : 
     733      3221129 :   bool has_name () const { return param_name != nullptr; }
     734              : 
     735              :   // TODO: is this better? Or is a "vis_block" better?
     736      3552707 :   Type &get_type ()
     737              :   {
     738      3552707 :     rust_assert (type != nullptr);
     739      3552707 :     return *type;
     740              :   }
     741              : 
     742      1101637 :   std::unique_ptr<Type> &get_type_ptr ()
     743              :   {
     744      1101637 :     rust_assert (type != nullptr);
     745      1101637 :     return type;
     746              :   }
     747              : 
     748       104784 :   FunctionParam *clone_param_impl () const override
     749              :   {
     750       104784 :     return new FunctionParam (*this);
     751              :   }
     752              : 
     753              :   void accept_vis (ASTVisitor &vis) override;
     754              : };
     755              : 
     756              : // Rust module item - abstract base class
     757              : class Module : public VisItem, public GlobContainer
     758              : {
     759              : public:
     760              :   // Type of the current module. A module can be either loaded or unloaded,
     761              :   // meaning that the items of the module can already be present or not. For
     762              :   // example, the following module would be loaded: `mod foo { fn bar() {} }`.
     763              :   // However, the module would be unloaded if it refers to an external file (i.e
     764              :   // `mod foo;`) and then become loaded upon expansion.
     765              :   enum ModuleKind
     766              :   {
     767              :     LOADED,
     768              :     UNLOADED,
     769              :   };
     770              : 
     771        72234 :   Identifier get_name () const { return module_name; }
     772              : 
     773              : private:
     774              :   Identifier module_name;
     775              :   location_t locus;
     776              :   ModuleKind kind;
     777              :   Unsafety safety;
     778              : 
     779              :   // Name of the file including the module
     780              :   std::string outer_filename;
     781              :   // bool has_inner_attrs;
     782              :   std::vector<Attribute> inner_attrs;
     783              :   // bool has_items;
     784              :   std::vector<std::unique_ptr<Item>> items;
     785              :   // Names of including inline modules (immediate parent is last in the list)
     786              :   std::vector<std::string> module_scope;
     787              : 
     788              :   // Filename the module refers to. Empty string on LOADED modules or if an
     789              :   // error occured when dealing with UNLOADED modules
     790              :   std::string module_file;
     791              : 
     792         3937 :   void clone_items (const std::vector<std::unique_ptr<Item>> &other_items)
     793              :   {
     794         3937 :     items.reserve (other_items.size ());
     795        39989 :     for (const auto &e : other_items)
     796        36052 :       items.push_back (e->clone_item ());
     797         3937 :   }
     798              : 
     799              : public:
     800              :   // Returns whether the module has items in its body.
     801              :   bool has_items () const { return !items.empty (); }
     802              : 
     803              :   // Returns whether the module has any inner attributes.
     804              :   bool has_inner_attrs () const { return !inner_attrs.empty (); }
     805              : 
     806              :   // Unloaded module constructor
     807          335 :   Module (Identifier module_name, Visibility visibility,
     808              :           std::vector<Attribute> outer_attrs, location_t locus, Unsafety safety,
     809              :           std::string outer_filename, std::vector<std::string> module_scope)
     810              :     : VisItem (std::move (visibility), std::move (outer_attrs)),
     811          335 :       module_name (module_name), locus (locus), kind (ModuleKind::UNLOADED),
     812          335 :       safety (safety), outer_filename (outer_filename),
     813          335 :       inner_attrs (std::vector<Attribute> ()),
     814          335 :       items (std::vector<std::unique_ptr<Item>> ()),
     815          335 :       module_scope (std::move (module_scope))
     816          335 :   {}
     817              : 
     818              :   // Loaded module constructor, with items
     819         1480 :   Module (Identifier name, location_t locus,
     820              :           std::vector<std::unique_ptr<Item>> items,
     821              :           Visibility visibility = Visibility::create_private (),
     822              :           Unsafety safety = Unsafety::Normal,
     823              :           std::vector<Attribute> inner_attrs = std::vector<Attribute> (),
     824              :           std::vector<Attribute> outer_attrs = std::vector<Attribute> ())
     825              :     : VisItem (std::move (visibility), std::move (outer_attrs)),
     826         1480 :       module_name (name), locus (locus), kind (ModuleKind::LOADED),
     827         1480 :       safety (safety), outer_filename (std::string ()),
     828         1480 :       inner_attrs (std::move (inner_attrs)), items (std::move (items))
     829         1480 :   {}
     830              : 
     831              :   // Copy constructor with vector clone
     832         4125 :   Module (Module const &other)
     833         4125 :     : VisItem (other), module_name (other.module_name), locus (other.locus),
     834         4125 :       kind (other.kind), safety (other.safety), inner_attrs (other.inner_attrs),
     835         4125 :       module_scope (other.module_scope)
     836              :   {
     837              :     // We need to check whether we are copying a loaded module or an unloaded
     838              :     // one. In the second case, clear the `items` vector.
     839         4125 :     if (other.kind == LOADED)
     840         3937 :       clone_items (other.items);
     841              :     else
     842          188 :       items.clear ();
     843         4125 :   }
     844              : 
     845              :   // Overloaded assignment operator with vector clone
     846              :   Module &operator= (Module const &other)
     847              :   {
     848              :     VisItem::operator= (other);
     849              : 
     850              :     module_name = other.module_name;
     851              :     locus = other.locus;
     852              :     kind = other.kind;
     853              :     inner_attrs = other.inner_attrs;
     854              :     module_scope = other.module_scope;
     855              : 
     856              :     // Likewise, we need to clear the `items` vector in case the other module is
     857              :     // unloaded
     858              :     if (kind == LOADED)
     859              :       clone_items (other.items);
     860              :     else
     861              :       items.clear ();
     862              : 
     863              :     return *this;
     864              :   }
     865              : 
     866              :   // Search for the filename associated with an external module, storing it in
     867              :   // module_file
     868              :   void process_file_path ();
     869              :   // Load the items contained in an external module
     870              :   void load_items ();
     871              : 
     872              :   void accept_vis (ASTVisitor &vis) override;
     873              : 
     874              :   /* Override that runs the function recursively on all items contained within
     875              :    * the module. */
     876              :   void add_crate_name (std::vector<std::string> &names) const override;
     877              : 
     878              :   // Returns the kind of the module
     879        13418 :   enum ModuleKind get_kind () const { return kind; }
     880              : 
     881         1732 :   Unsafety get_unsafety () const { return safety; }
     882              : 
     883              :   // TODO: think of better way to do this - mutable getter seems dodgy
     884              :   const std::vector<Attribute> &get_inner_attrs () const { return inner_attrs; }
     885        80350 :   std::vector<Attribute> &get_inner_attrs () { return inner_attrs; }
     886              : 
     887              :   const std::vector<std::unique_ptr<Item>> &get_items () const { return items; }
     888        93939 :   std::vector<std::unique_ptr<Item>> &get_items () { return items; }
     889              : 
     890              :   std::vector<std::unique_ptr<AST::Item>> take_items ()
     891              :   {
     892              :     return std::move (items);
     893              :   }
     894              : 
     895              :   void set_items (std::vector<std::unique_ptr<AST::Item>> &&new_items)
     896              :   {
     897              :     items = std::move (new_items);
     898              :   }
     899              : 
     900              :   // move constructors
     901              :   Module (Module &&other) = default;
     902              :   Module &operator= (Module &&other) = default;
     903              : 
     904              :   std::string as_string () const override;
     905              : 
     906        16666 :   location_t get_locus () const override final { return locus; }
     907              : 
     908              :   // Invalid if name is empty, so base stripping on that.
     909          158 :   void mark_for_strip () override { module_name = {""}; }
     910        12294 :   bool is_marked_for_strip () const override { return module_name.empty (); }
     911              : 
     912          542 :   Item::Kind get_item_kind () const override { return Item::Kind::Module; }
     913              : 
     914              : protected:
     915              :   /* Use covariance to implement clone function as returning this object
     916              :    * rather than base */
     917         2393 :   Module *clone_item_impl () const override { return new Module (*this); }
     918              : 
     919        14076 :   GlobContainer::Kind get_glob_container_kind () const override
     920              :   {
     921        14076 :     return GlobContainer::Kind::Module;
     922              :   }
     923              : };
     924              : 
     925              : // Rust extern crate declaration AST node
     926              : class ExternCrate : public VisItem
     927              : {
     928              :   // this is either an identifier or "self", with self parsed to string
     929              :   std::string referenced_crate;
     930              :   // bool has_as_clause;
     931              :   // AsClause as_clause;
     932              :   // this is either an identifier or "_", with _ parsed to string
     933              :   std::string as_clause_name;
     934              : 
     935              :   location_t locus;
     936              : 
     937              :   /* e.g.
     938              :       "extern crate foo as _"
     939              :       "extern crate foo"
     940              :       "extern crate std as cool_std"  */
     941              : public:
     942              :   std::string as_string () const override;
     943              : 
     944              :   // Returns whether extern crate declaration has an as clause.
     945          565 :   bool has_as_clause () const { return !as_clause_name.empty (); }
     946              : 
     947              :   /* Returns whether extern crate declaration references the current crate
     948              :    * (i.e. self). */
     949          173 :   bool references_self () const { return referenced_crate == "self"; }
     950              : 
     951              :   // Constructor
     952           70 :   ExternCrate (std::string referenced_crate, Visibility visibility,
     953              :                std::vector<Attribute> outer_attrs, location_t locus,
     954              :                std::string as_clause_name = std::string ())
     955              :     : VisItem (std::move (visibility), std::move (outer_attrs)),
     956           70 :       referenced_crate (std::move (referenced_crate)),
     957           70 :       as_clause_name (std::move (as_clause_name)), locus (locus)
     958           70 :   {}
     959              : 
     960          363 :   location_t get_locus () const override final { return locus; }
     961              : 
     962              :   void accept_vis (ASTVisitor &vis) override;
     963              : 
     964          990 :   const std::string &get_referenced_crate () const { return referenced_crate; }
     965           82 :   const std::string &get_as_clause () const { return as_clause_name; }
     966              : 
     967              :   // Override that adds extern crate name in decl to passed list of names.
     968            0 :   void add_crate_name (std::vector<std::string> &names) const override
     969              :   {
     970            0 :     names.push_back (referenced_crate);
     971            0 :   }
     972              : 
     973              :   // Invalid if crate name is empty, so base stripping on that.
     974            2 :   void mark_for_strip () override { referenced_crate = ""; }
     975          135 :   bool is_marked_for_strip () const override
     976              :   {
     977          135 :     return referenced_crate.empty ();
     978              :   }
     979              : 
     980            6 :   Item::Kind get_item_kind () const override { return Item::Kind::ExternCrate; }
     981              : 
     982              : protected:
     983              :   /* Use covariance to implement clone function as returning this object
     984              :    * rather than base */
     985           67 :   ExternCrate *clone_item_impl () const override
     986              :   {
     987           67 :     return new ExternCrate (*this);
     988              :   }
     989              : };
     990              : 
     991              : // The path-ish thing referred to in a use declaration - abstract base class
     992              : class UseTree
     993              : {
     994              :   location_t locus;
     995              :   NodeId node_id;
     996              : 
     997              : public:
     998              :   enum Kind
     999              :   {
    1000              :     Glob,
    1001              :     Rebind,
    1002              :     List,
    1003              :   };
    1004              : 
    1005              :   virtual ~UseTree () {}
    1006              : 
    1007              :   // Overload assignment operator to clone
    1008              :   UseTree &operator= (UseTree const &other)
    1009              :   {
    1010              :     locus = other.locus;
    1011              : 
    1012              :     return *this;
    1013              :   }
    1014              : 
    1015         1451 :   UseTree (const UseTree &other) = default;
    1016              : 
    1017              :   // move constructors
    1018              :   UseTree (UseTree &&other) = default;
    1019              :   UseTree &operator= (UseTree &&other) = default;
    1020              : 
    1021              :   // Unique pointer custom clone function
    1022         9901 :   std::unique_ptr<UseTree> clone_use_tree () const
    1023              :   {
    1024         9901 :     return std::unique_ptr<UseTree> (clone_use_tree_impl ());
    1025              :   }
    1026              : 
    1027              :   virtual std::string as_string () const = 0;
    1028              :   virtual Kind get_kind () const = 0;
    1029              : 
    1030           22 :   location_t get_locus () const { return locus; }
    1031          966 :   NodeId get_node_id () const { return node_id; }
    1032              : 
    1033              :   virtual void accept_vis (ASTVisitor &vis) = 0;
    1034              : 
    1035              : protected:
    1036              :   // Clone function implementation as pure virtual method
    1037              :   virtual UseTree *clone_use_tree_impl () const = 0;
    1038              : 
    1039         3932 :   UseTree (location_t locus)
    1040         3932 :     : locus (locus), node_id (Analysis::Mappings::get ().get_next_node_id ())
    1041         3932 :   {}
    1042              : };
    1043              : 
    1044              : // Use tree with a glob (wildcard) operator
    1045              : class UseTreeGlob : public UseTree
    1046              : {
    1047              : public:
    1048              :   enum PathType
    1049              :   {
    1050              :     NO_PATH,
    1051              :     GLOBAL,
    1052              :     PATH_PREFIXED
    1053              :   };
    1054              : 
    1055              : private:
    1056              :   PathType glob_type;
    1057              :   SimplePath path;
    1058              : 
    1059              : public:
    1060          245 :   UseTreeGlob (PathType glob_type, SimplePath path, location_t locus)
    1061          245 :     : UseTree (locus), glob_type (glob_type), path (std::move (path))
    1062              :   {
    1063          245 :     if (this->glob_type != PATH_PREFIXED)
    1064              :       {
    1065              :         // compiler implementation error if there is a path with a
    1066              :         // non-path-prefixed use tree glob
    1067            0 :         rust_assert (!has_path ());
    1068              :       }
    1069              :     // TODO: do path-prefixed paths also have to have a path? If so, have an
    1070              :     // assert for that too.
    1071          245 :   }
    1072              : 
    1073              :   /* Returns whether has path. Should be made redundant by PathType
    1074              :    * PATH_PREFIXED. */
    1075         4216 :   bool has_path () const { return !path.is_empty (); }
    1076              : 
    1077              :   std::string as_string () const override;
    1078              : 
    1079              :   void accept_vis (ASTVisitor &vis) override;
    1080              : 
    1081           32 :   PathType get_glob_type () const { return glob_type; }
    1082              : 
    1083         6695 :   Kind get_kind () const override { return Glob; }
    1084              : 
    1085         4198 :   SimplePath get_path () const
    1086              :   {
    1087         4198 :     rust_assert (has_path ());
    1088         4198 :     return path;
    1089              :   }
    1090              : 
    1091         8228 :   SimplePath &get_path () { return path; }
    1092              : 
    1093              :   /* TODO: find way to ensure only PATH_PREFIXED glob_type has path - factory
    1094              :    * methods? */
    1095              : protected:
    1096              :   /* Use covariance to implement clone function as returning this object
    1097              :    * rather than base */
    1098          596 :   UseTreeGlob *clone_use_tree_impl () const override
    1099              :   {
    1100          596 :     return new UseTreeGlob (*this);
    1101              :   }
    1102              : };
    1103              : 
    1104              : // Use tree with a list of paths with a common prefix
    1105              : class UseTreeList : public UseTree
    1106              : {
    1107              : public:
    1108              :   enum PathType
    1109              :   {
    1110              :     NO_PATH,
    1111              :     GLOBAL,
    1112              :     PATH_PREFIXED
    1113              :   };
    1114              : 
    1115              : private:
    1116              :   PathType path_type;
    1117              :   SimplePath path;
    1118              : 
    1119              :   std::vector<std::unique_ptr<UseTree>> trees;
    1120              : 
    1121              : public:
    1122          587 :   UseTreeList (PathType path_type, SimplePath path,
    1123              :                std::vector<std::unique_ptr<UseTree>> trees, location_t locus)
    1124          587 :     : UseTree (locus), path_type (path_type), path (std::move (path)),
    1125          587 :       trees (std::move (trees))
    1126              :   {
    1127          587 :     if (this->path_type != PATH_PREFIXED)
    1128              :       {
    1129              :         // compiler implementation error if there is a path with a
    1130              :         // non-path-prefixed use tree glob
    1131            0 :         rust_assert (!has_path ());
    1132              :       }
    1133              :     // TODO: do path-prefixed paths also have to have a path? If so, have an
    1134              :     // assert for that too.
    1135          587 :   }
    1136              : 
    1137              :   // copy constructor with vector clone
    1138         1451 :   UseTreeList (UseTreeList const &other)
    1139         1451 :     : UseTree (other), path_type (other.path_type), path (other.path)
    1140              :   {
    1141         1451 :     trees.reserve (other.trees.size ());
    1142         6067 :     for (const auto &e : other.trees)
    1143         4616 :       trees.push_back (e->clone_use_tree ());
    1144         1451 :   }
    1145              : 
    1146              :   // overloaded assignment operator with vector clone
    1147              :   UseTreeList &operator= (UseTreeList const &other)
    1148              :   {
    1149              :     UseTree::operator= (other);
    1150              :     path_type = other.path_type;
    1151              :     path = other.path;
    1152              : 
    1153              :     trees.reserve (other.trees.size ());
    1154              :     for (const auto &e : other.trees)
    1155              :       trees.push_back (e->clone_use_tree ());
    1156              : 
    1157              :     return *this;
    1158              :   }
    1159              : 
    1160              :   // move constructors
    1161              :   UseTreeList (UseTreeList &&other) = default;
    1162              :   UseTreeList &operator= (UseTreeList &&other) = default;
    1163              : 
    1164              :   // Returns whether has path. Should be made redundant by path_type.
    1165        17868 :   bool has_path () const { return !path.is_empty (); }
    1166              : 
    1167              :   // Returns whether has inner tree elements.
    1168          171 :   bool has_trees () const { return !trees.empty (); }
    1169              : 
    1170              :   std::string as_string () const override;
    1171              : 
    1172          171 :   PathType get_path_type () { return path_type; }
    1173              : 
    1174              :   void accept_vis (ASTVisitor &vis) override;
    1175              : 
    1176        17866 :   Kind get_kind () const override { return List; }
    1177         9647 :   SimplePath get_path () const
    1178              :   {
    1179         9647 :     rust_assert (has_path ());
    1180         9647 :     return path;
    1181              :   }
    1182              : 
    1183        28607 :   SimplePath &get_path () { return path; }
    1184              : 
    1185          175 :   std::vector<std::unique_ptr<UseTree>> &get_trees () { return trees; }
    1186              : 
    1187              :   const std::vector<std::unique_ptr<UseTree>> &get_trees () const
    1188              :   {
    1189         9651 :     return trees;
    1190              :   }
    1191              : 
    1192              :   // TODO: find way to ensure only PATH_PREFIXED path_type has path - factory
    1193              :   // methods?
    1194              : protected:
    1195              :   /* Use covariance to implement clone function as returning this object
    1196              :    * rather than base */
    1197         1451 :   UseTreeList *clone_use_tree_impl () const override
    1198              :   {
    1199         1451 :     return new UseTreeList (*this);
    1200              :   }
    1201              : };
    1202              : 
    1203              : // Use tree where it rebinds the module name as something else
    1204              : class UseTreeRebind : public UseTree
    1205              : {
    1206              : public:
    1207              :   enum NewBindType
    1208              :   {
    1209              :     NONE,
    1210              :     IDENTIFIER,
    1211              :     WILDCARD
    1212              :   };
    1213              : 
    1214              : private:
    1215              :   SimplePath path;
    1216              : 
    1217              :   NewBindType bind_type;
    1218              :   Identifier identifier; // only if NewBindType is IDENTIFIER
    1219              : 
    1220              : public:
    1221         3100 :   UseTreeRebind (NewBindType bind_type, SimplePath path, location_t locus,
    1222              :                  Identifier identifier = std::string ())
    1223         3100 :     : UseTree (locus), path (std::move (path)), bind_type (bind_type),
    1224         3100 :       identifier (std::move (identifier))
    1225         3100 :   {}
    1226              : 
    1227              :   // Returns whether has path (this should always be true).
    1228        45944 :   bool has_path () const { return !path.is_empty (); }
    1229              : 
    1230              :   // Returns whether has identifier (or, rather, is allowed to).
    1231          396 :   bool has_identifier () const { return bind_type == IDENTIFIER; }
    1232              : 
    1233              :   std::string as_string () const override;
    1234              : 
    1235        52681 :   NewBindType get_new_bind_type () const { return bind_type; }
    1236              : 
    1237              :   void accept_vis (ASTVisitor &vis) override;
    1238              : 
    1239        62816 :   Kind get_kind () const override { return Rebind; }
    1240              : 
    1241        45944 :   const SimplePath &get_path () const
    1242              :   {
    1243        45944 :     rust_assert (has_path ());
    1244        45944 :     return path;
    1245              :   }
    1246              : 
    1247        76464 :   SimplePath &get_path () { return path; }
    1248              : 
    1249          396 :   const Identifier &get_identifier () const
    1250              :   {
    1251          396 :     rust_assert (has_identifier ());
    1252          396 :     return identifier;
    1253              :   }
    1254              : 
    1255              :   // TODO: find way to ensure only PATH_PREFIXED path_type has path - factory
    1256              :   // methods?
    1257              : protected:
    1258              :   /* Use covariance to implement clone function as returning this object
    1259              :    * rather than base */
    1260         7854 :   virtual UseTreeRebind *clone_use_tree_impl () const override
    1261              :   {
    1262         7854 :     return new UseTreeRebind (*this);
    1263              :   }
    1264              : };
    1265              : 
    1266              : // Rust use declaration (i.e. for modules) AST node
    1267              : class UseDeclaration : public VisItem
    1268              : {
    1269              :   std::unique_ptr<UseTree> use_tree;
    1270              :   location_t locus;
    1271              : 
    1272              : public:
    1273              :   std::string as_string () const override;
    1274              : 
    1275         2048 :   UseDeclaration (std::unique_ptr<UseTree> use_tree, Visibility visibility,
    1276              :                   std::vector<Attribute> outer_attrs, location_t locus)
    1277              :     : VisItem (std::move (visibility), std::move (outer_attrs)),
    1278         2048 :       use_tree (std::move (use_tree)), locus (locus)
    1279         2048 :   {}
    1280              : 
    1281              :   // Copy constructor with clone
    1282         5285 :   UseDeclaration (UseDeclaration const &other)
    1283         5285 :     : VisItem (other), locus (other.locus)
    1284              :   {
    1285              :     // guard to prevent null dereference (only required if error state)
    1286         5285 :     if (other.use_tree != nullptr)
    1287         5285 :       use_tree = other.use_tree->clone_use_tree ();
    1288         5285 :   }
    1289              : 
    1290              :   // Overloaded assignment operator to clone
    1291              :   UseDeclaration &operator= (UseDeclaration const &other)
    1292              :   {
    1293              :     VisItem::operator= (other);
    1294              :     // visibility = other.visibility->clone_visibility();
    1295              :     // outer_attrs = other.outer_attrs;
    1296              :     locus = other.locus;
    1297              : 
    1298              :     // guard to prevent null dereference (only required if error state)
    1299              :     if (other.use_tree != nullptr)
    1300              :       use_tree = other.use_tree->clone_use_tree ();
    1301              :     else
    1302              :       use_tree = nullptr;
    1303              : 
    1304              :     return *this;
    1305              :   }
    1306              : 
    1307              :   // move constructors
    1308              :   UseDeclaration (UseDeclaration &&other) = default;
    1309              :   UseDeclaration &operator= (UseDeclaration &&other) = default;
    1310              : 
    1311          720 :   location_t get_locus () const override final { return locus; }
    1312              : 
    1313       171095 :   std::unique_ptr<UseTree> &get_tree () { return use_tree; }
    1314              : 
    1315              :   const std::unique_ptr<UseTree> &get_tree () const { return use_tree; }
    1316              : 
    1317              :   void accept_vis (ASTVisitor &vis) override;
    1318              : 
    1319              :   // Invalid if use tree is null, so base stripping on that.
    1320           51 :   void mark_for_strip () override { use_tree = nullptr; }
    1321        28865 :   bool is_marked_for_strip () const override { return use_tree == nullptr; }
    1322              : 
    1323          502 :   Item::Kind get_item_kind () const override
    1324              :   {
    1325          502 :     return Item::Kind::UseDeclaration;
    1326              :   }
    1327              : 
    1328              : protected:
    1329              :   /* Use covariance to implement clone function as returning this object
    1330              :    * rather than base */
    1331         3403 :   UseDeclaration *clone_item_impl () const override
    1332              :   {
    1333         3403 :     return new UseDeclaration (*this);
    1334              :   }
    1335              : };
    1336              : 
    1337              : class LetStmt;
    1338              : 
    1339              : // Rust function declaration AST node
    1340              : class Function : public VisItem, public AssociatedItem, public ExternalItem
    1341              : {
    1342              :   FunctionQualifiers qualifiers;
    1343              :   Identifier function_name;
    1344              :   std::vector<std::unique_ptr<GenericParam>> generic_params;
    1345              :   std::vector<std::unique_ptr<Param>> function_params;
    1346              :   std::unique_ptr<Type> return_type;
    1347              :   WhereClause where_clause;
    1348              :   tl::optional<std::unique_ptr<BlockExpr>> function_body;
    1349              :   location_t locus;
    1350              :   bool is_external_function;
    1351              : 
    1352              : public:
    1353              :   std::string as_string () const override;
    1354              : 
    1355              :   // Returns whether function has generic parameters.
    1356        54174 :   bool has_generics () const { return !generic_params.empty (); }
    1357              : 
    1358              :   // Returns whether function has regular parameters.
    1359        34806 :   bool has_function_params () const { return !function_params.empty (); }
    1360              : 
    1361              :   // Returns whether function has return type - if not, it is void.
    1362      4350221 :   bool has_return_type () const { return return_type != nullptr; }
    1363              : 
    1364              :   // Returns whether function has a where clause.
    1365      3490135 :   bool has_where_clause () const { return !where_clause.is_empty (); }
    1366              : 
    1367        56934 :   bool has_self_param () const
    1368              :   {
    1369        56934 :     return function_params.size () > 0 && function_params[0]->is_self ();
    1370              :   }
    1371              : 
    1372      5033612 :   bool has_body () const { return function_body.has_value (); }
    1373              : 
    1374        27877 :   bool is_default () const { return qualifiers.is_default (); }
    1375              : 
    1376              :   // Mega-constructor with all possible fields
    1377        36931 :   Function (Identifier function_name, FunctionQualifiers qualifiers,
    1378              :             std::vector<std::unique_ptr<GenericParam>> generic_params,
    1379              :             std::vector<std::unique_ptr<Param>> function_params,
    1380              :             std::unique_ptr<Type> return_type, WhereClause where_clause,
    1381              :             tl::optional<std::unique_ptr<BlockExpr>> function_body,
    1382              :             Visibility vis, std::vector<Attribute> outer_attrs,
    1383              :             location_t locus, bool is_external_function = false)
    1384              :     : VisItem (std::move (vis), std::move (outer_attrs)),
    1385        36931 :       ExternalItem (Stmt::node_id), qualifiers (std::move (qualifiers)),
    1386        36931 :       function_name (std::move (function_name)),
    1387        36931 :       generic_params (std::move (generic_params)),
    1388        36931 :       function_params (std::move (function_params)),
    1389        36931 :       return_type (std::move (return_type)),
    1390        36931 :       where_clause (std::move (where_clause)),
    1391        36931 :       function_body (std::move (function_body)), locus (locus),
    1392        36931 :       is_external_function (is_external_function)
    1393        36931 :   {}
    1394              : 
    1395              :   // TODO: add constructor with less fields
    1396              : 
    1397              :   // Copy constructor with clone
    1398              :   Function (Function const &other);
    1399              : 
    1400              :   // Overloaded assignment operator to clone
    1401              :   Function &operator= (Function const &other);
    1402              : 
    1403              :   // move constructors
    1404              :   Function (Function &&other) = default;
    1405              :   Function &operator= (Function &&other) = default;
    1406              : 
    1407       589122 :   location_t get_locus () const override final { return locus; }
    1408              : 
    1409              :   void accept_vis (ASTVisitor &vis) override;
    1410              : 
    1411         4445 :   bool is_variadic () const
    1412              :   {
    1413         4445 :     return function_params.size () != 0
    1414         4445 :            && function_params.back ()->is_variadic ();
    1415              :   }
    1416              : 
    1417        70086 :   bool is_external () const { return is_external_function; }
    1418              : 
    1419              :   // Invalid if block is null, so base stripping on that.
    1420           62 :   void mark_for_strip () override { function_body = nullptr; }
    1421       508305 :   bool is_marked_for_strip () const override
    1422              :   {
    1423       508305 :     return function_body == nullptr;
    1424              :   }
    1425              : 
    1426      1316853 :   std::vector<std::unique_ptr<Param>> &get_function_params ()
    1427              :   {
    1428      4461631 :     return function_params;
    1429              :   }
    1430              :   const std::vector<std::unique_ptr<Param>> &get_function_params () const
    1431              :   {
    1432              :     return function_params;
    1433              :   }
    1434              : 
    1435         5181 :   std::vector<std::unique_ptr<GenericParam>> &get_generic_params ()
    1436              :   {
    1437      3475800 :     return generic_params;
    1438              :   }
    1439              :   const std::vector<std::unique_ptr<GenericParam>> &get_generic_params () const
    1440              :   {
    1441              :     return generic_params;
    1442              :   }
    1443              : 
    1444              :   // TODO: is this better? Or is a "vis_block" better?
    1445      4380150 :   tl::optional<std::unique_ptr<BlockExpr>> &get_definition ()
    1446              :   {
    1447      4380150 :     return function_body;
    1448              :   }
    1449              : 
    1450              :   const FunctionQualifiers &get_qualifiers () const { return qualifiers; }
    1451              : 
    1452      3084397 :   FunctionQualifiers &get_qualifiers () { return qualifiers; }
    1453              : 
    1454      1571557 :   Identifier get_function_name () const { return function_name; }
    1455              : 
    1456              :   // TODO: is this better? Or is a "vis_block" better?
    1457       114058 :   WhereClause &get_where_clause () { return where_clause; }
    1458              : 
    1459              :   // TODO: is this better? Or is a "vis_block" better?
    1460      2862883 :   Type &get_return_type ()
    1461              :   {
    1462      2862883 :     rust_assert (has_return_type ());
    1463      2862883 :     return *return_type;
    1464              :   }
    1465              : 
    1466       834670 :   std::unique_ptr<Type> &get_return_type_ptr ()
    1467              :   {
    1468       834670 :     rust_assert (has_return_type ());
    1469       834670 :     return return_type;
    1470              :   }
    1471              : 
    1472        18780 :   Param &get_self_param ()
    1473              :   {
    1474        18780 :     rust_assert (has_self_param ());
    1475        18780 :     return *function_params[0];
    1476              :   }
    1477              :   const Param &get_self_param () const
    1478              :   {
    1479              :     rust_assert (has_self_param ());
    1480              :     return *function_params[0];
    1481              :   }
    1482              : 
    1483              :   // ExternalItem::node_id is same as Stmt::node_id
    1484      3676607 :   NodeId get_node_id () const override { return Stmt::node_id; }
    1485              : 
    1486       144261 :   Item::Kind get_item_kind () const override { return Item::Kind::Function; }
    1487              : 
    1488              : protected:
    1489              :   /* Use covariance to implement clone function as returning this object
    1490              :    * rather than base */
    1491        13927 :   Function *clone_item_impl () const override { return new Function (*this); }
    1492              : 
    1493              :   /* Use covariance to implement clone function as returning this object
    1494              :    * rather than base */
    1495        93711 :   Function *clone_associated_item_impl () const override
    1496              :   {
    1497        93711 :     return new Function (*this);
    1498              :   }
    1499              : 
    1500              :   /* Use covariance to implement clone function as returning this object
    1501              :    * rather than base */
    1502         9008 :   Function *clone_external_item_impl () const override
    1503              :   {
    1504         9008 :     return new Function (*this);
    1505              :   }
    1506              : };
    1507              : 
    1508              : // Rust type alias (i.e. typedef) AST node
    1509              : class TypeAlias : public VisItem, public AssociatedItem
    1510              : {
    1511              :   Identifier new_type_name;
    1512              : 
    1513              :   // bool has_generics;
    1514              :   // Generics generic_params;
    1515              :   std::vector<std::unique_ptr<GenericParam>> generic_params; // inlined
    1516              : 
    1517              :   // bool has_where_clause;
    1518              :   WhereClause where_clause;
    1519              : 
    1520              :   std::unique_ptr<Type> existing_type;
    1521              : 
    1522              :   location_t locus;
    1523              : 
    1524              : public:
    1525              :   std::string as_string () const override;
    1526              : 
    1527              :   // Returns whether type alias has generic parameters.
    1528         5744 :   bool has_generics () const { return !generic_params.empty (); }
    1529              : 
    1530              :   // Returns whether type alias has a where clause.
    1531       671257 :   bool has_where_clause () const { return !where_clause.is_empty (); }
    1532              : 
    1533              :   // Mega-constructor with all possible fields
    1534         4367 :   TypeAlias (Identifier new_type_name,
    1535              :              std::vector<std::unique_ptr<GenericParam>> generic_params,
    1536              :              WhereClause where_clause, std::unique_ptr<Type> existing_type,
    1537              :              Visibility vis, std::vector<Attribute> outer_attrs,
    1538              :              location_t locus)
    1539              :     : VisItem (std::move (vis), std::move (outer_attrs)),
    1540         4367 :       new_type_name (std::move (new_type_name)),
    1541         4367 :       generic_params (std::move (generic_params)),
    1542         4367 :       where_clause (std::move (where_clause)),
    1543         4367 :       existing_type (std::move (existing_type)), locus (locus)
    1544         4367 :   {}
    1545              : 
    1546              :   // Copy constructor
    1547        27964 :   TypeAlias (TypeAlias const &other)
    1548        27964 :     : VisItem (other), new_type_name (other.new_type_name),
    1549        27964 :       where_clause (other.where_clause), locus (other.locus)
    1550              :   {
    1551              :     // guard to prevent null dereference (only required if error state)
    1552        27964 :     if (other.existing_type != nullptr)
    1553        27964 :       existing_type = other.existing_type->clone_type ();
    1554              : 
    1555        27964 :     generic_params.reserve (other.generic_params.size ());
    1556        28038 :     for (const auto &e : other.generic_params)
    1557           74 :       generic_params.push_back (e->clone_generic_param ());
    1558        27964 :   }
    1559              : 
    1560              :   // Overloaded assignment operator to clone
    1561              :   TypeAlias &operator= (TypeAlias const &other)
    1562              :   {
    1563              :     VisItem::operator= (other);
    1564              :     new_type_name = other.new_type_name;
    1565              :     where_clause = other.where_clause;
    1566              :     // visibility = other.visibility->clone_visibility();
    1567              :     // outer_attrs = other.outer_attrs;
    1568              :     locus = other.locus;
    1569              : 
    1570              :     // guard to prevent null dereference (only required if error state)
    1571              :     if (other.existing_type != nullptr)
    1572              :       existing_type = other.existing_type->clone_type ();
    1573              :     else
    1574              :       existing_type = nullptr;
    1575              : 
    1576              :     generic_params.reserve (other.generic_params.size ());
    1577              :     for (const auto &e : other.generic_params)
    1578              :       generic_params.push_back (e->clone_generic_param ());
    1579              : 
    1580              :     return *this;
    1581              :   }
    1582              : 
    1583              :   // move constructors
    1584              :   TypeAlias (TypeAlias &&other) = default;
    1585              :   TypeAlias &operator= (TypeAlias &&other) = default;
    1586              : 
    1587       100785 :   location_t get_locus () const override final { return locus; }
    1588              : 
    1589              :   // needed to override AssociatedItem::get_node_id
    1590       570068 :   NodeId get_node_id () const override final { return VisItem::get_node_id (); }
    1591              : 
    1592              :   void accept_vis (ASTVisitor &vis) override;
    1593              : 
    1594              :   // Invalid if existing type is null, so base stripping on that.
    1595            0 :   void mark_for_strip () override { existing_type = nullptr; }
    1596        94898 :   bool is_marked_for_strip () const override
    1597              :   {
    1598        94898 :     return existing_type == nullptr;
    1599              :   }
    1600              : 
    1601           48 :   std::vector<std::unique_ptr<GenericParam>> &get_generic_params ()
    1602              :   {
    1603       669840 :     return generic_params;
    1604              :   }
    1605              :   const std::vector<std::unique_ptr<GenericParam>> &get_generic_params () const
    1606              :   {
    1607              :     return generic_params;
    1608              :   }
    1609              : 
    1610              :   // TODO: is this better? Or is a "vis_block" better?
    1611            0 :   WhereClause &get_where_clause () { return where_clause; }
    1612              : 
    1613              :   // TODO: is this better? Or is a "vis_block" better?
    1614       670778 :   Type &get_type_aliased ()
    1615              :   {
    1616       670778 :     rust_assert (existing_type != nullptr);
    1617       670778 :     return *existing_type;
    1618              :   }
    1619              : 
    1620       185675 :   std::unique_ptr<Type> &get_type_aliased_ptr ()
    1621              :   {
    1622       185675 :     rust_assert (existing_type != nullptr);
    1623       185675 :     return existing_type;
    1624              :   }
    1625              : 
    1626       480701 :   Identifier get_new_type_name () const { return new_type_name; }
    1627              : 
    1628           94 :   Item::Kind get_item_kind () const override { return Item::Kind::TypeAlias; }
    1629              : 
    1630              : protected:
    1631              :   /* Use covariance to implement clone function as returning this object
    1632              :    * rather than base */
    1633          172 :   TypeAlias *clone_item_impl () const override { return new TypeAlias (*this); }
    1634              : 
    1635              :   /* Use covariance to implement clone function as returning this object
    1636              :    * rather than base */
    1637        23440 :   TypeAlias *clone_associated_item_impl () const override
    1638              :   {
    1639        23440 :     return new TypeAlias (*this);
    1640              :   }
    1641              : };
    1642              : 
    1643              : // Rust trait alias AST node
    1644              : // like a type alias, but for traits
    1645              : // unstable but used in core
    1646              : class TraitAlias : public VisItem
    1647              : {
    1648              :   Identifier alias_name;
    1649              : 
    1650              :   // bool has_generics;
    1651              :   // Generics generic_params;
    1652              :   std::vector<std::unique_ptr<GenericParam>> generic_params; // inlined
    1653              : 
    1654              :   // bool has_where_clause;
    1655              :   WhereClause where_clause;
    1656              : 
    1657              :   std::vector<std::unique_ptr<TypeParamBound>> alias_bounds;
    1658              : 
    1659              :   location_t locus;
    1660              : 
    1661              :   bool m_mark_for_strip;
    1662              : 
    1663              : public:
    1664              :   std::string as_string () const override;
    1665              : 
    1666              :   // Returns whether type alias has generic parameters.
    1667            0 :   bool has_generics () const { return !generic_params.empty (); }
    1668              : 
    1669              :   // Returns whether type alias has a where clause.
    1670           44 :   bool has_where_clause () const { return !where_clause.is_empty (); }
    1671              : 
    1672              :   // Mega-constructor with all possible fields
    1673            2 :   TraitAlias (Identifier alias_name,
    1674              :               std::vector<std::unique_ptr<GenericParam>> generic_params,
    1675              :               WhereClause where_clause,
    1676              :               std::vector<std::unique_ptr<TypeParamBound>> alias_bounds,
    1677              :               Visibility vis, std::vector<Attribute> outer_attrs,
    1678              :               location_t locus)
    1679              :     : VisItem (std::move (vis), std::move (outer_attrs)),
    1680            4 :       alias_name (std::move (alias_name)),
    1681            2 :       generic_params (std::move (generic_params)),
    1682            2 :       where_clause (std::move (where_clause)),
    1683            2 :       alias_bounds (std::move (alias_bounds)), locus (locus),
    1684            2 :       m_mark_for_strip (false)
    1685            2 :   {}
    1686              : 
    1687              :   // Copy constructor
    1688            2 :   TraitAlias (TraitAlias const &other)
    1689            2 :     : VisItem (other), alias_name (other.alias_name),
    1690            2 :       where_clause (other.where_clause), locus (other.locus)
    1691              :   {
    1692            2 :     generic_params.reserve (other.generic_params.size ());
    1693            2 :     for (const auto &e : other.generic_params)
    1694            0 :       generic_params.push_back (e->clone_generic_param ());
    1695              : 
    1696            2 :     alias_bounds.reserve (other.alias_bounds.size ());
    1697            4 :     for (const auto &b : other.alias_bounds)
    1698            2 :       alias_bounds.push_back (b->clone_type_param_bound ());
    1699            2 :   }
    1700              : 
    1701              :   // Overloaded assignment operator to clone
    1702              :   TraitAlias &operator= (TraitAlias const &other)
    1703              :   {
    1704              :     VisItem::operator= (other);
    1705              :     alias_name = other.alias_name;
    1706              :     where_clause = other.where_clause;
    1707              :     // visibility = other.visibility->clone_visibility();
    1708              :     // outer_attrs = other.outer_attrs;
    1709              :     locus = other.locus;
    1710              : 
    1711              :     generic_params.clear ();
    1712              :     generic_params.reserve (other.generic_params.size ());
    1713              :     for (const auto &e : other.generic_params)
    1714              :       generic_params.push_back (e->clone_generic_param ());
    1715              : 
    1716              :     alias_bounds.clear ();
    1717              :     alias_bounds.reserve (other.alias_bounds.size ());
    1718              :     for (const auto &b : other.alias_bounds)
    1719              :       alias_bounds.push_back (b->clone_type_param_bound ());
    1720              : 
    1721              :     return *this;
    1722              :   }
    1723              : 
    1724              :   // move constructors
    1725              :   TraitAlias (TraitAlias &&other) = default;
    1726              :   TraitAlias &operator= (TraitAlias &&other) = default;
    1727              : 
    1728            8 :   location_t get_locus () const override final { return locus; }
    1729              : 
    1730              :   // needed to override AssociatedItem::get_node_id
    1731           22 :   NodeId get_node_id () const override final { return VisItem::get_node_id (); }
    1732              : 
    1733              :   void accept_vis (ASTVisitor &vis) override;
    1734              : 
    1735            0 :   void mark_for_strip () override { m_mark_for_strip = true; }
    1736            4 :   bool is_marked_for_strip () const override { return m_mark_for_strip; }
    1737              : 
    1738            0 :   std::vector<std::unique_ptr<GenericParam>> &get_generic_params ()
    1739              :   {
    1740           44 :     return generic_params;
    1741              :   }
    1742              :   const std::vector<std::unique_ptr<GenericParam>> &get_generic_params () const
    1743              :   {
    1744              :     return generic_params;
    1745              :   }
    1746              : 
    1747              :   // TODO: is this better? Or is a "vis_block" better?
    1748            0 :   WhereClause &get_where_clause () { return where_clause; }
    1749              : 
    1750            0 :   std::vector<std::unique_ptr<TypeParamBound>> &get_alias_bounds ()
    1751              :   {
    1752           44 :     return alias_bounds;
    1753              :   }
    1754              :   const std::vector<std::unique_ptr<TypeParamBound>> &get_alias_bounds () const
    1755              :   {
    1756              :     return alias_bounds;
    1757              :   }
    1758              : 
    1759           30 :   const Identifier &get_alias_name () const { return alias_name; }
    1760              : 
    1761            0 :   Item::Kind get_item_kind () const override { return Item::Kind::TraitAlias; }
    1762              : 
    1763              : protected:
    1764              :   /* Use covariance to implement clone function as returning this object
    1765              :    * rather than base */
    1766            2 :   TraitAlias *clone_item_impl () const override
    1767              :   {
    1768            2 :     return new TraitAlias (*this);
    1769              :   }
    1770              : };
    1771              : 
    1772              : // Rust base struct declaration AST node - abstract base class
    1773              : class Struct : public VisItem
    1774              : {
    1775              : protected:
    1776              :   // protected to enable access by derived classes - allows better as_string
    1777              :   Identifier struct_name;
    1778              : 
    1779              :   // bool has_generics;
    1780              :   // Generics generic_params;
    1781              :   std::vector<std::unique_ptr<GenericParam>> generic_params; // inlined
    1782              : 
    1783              :   // bool has_where_clause;
    1784              :   WhereClause where_clause;
    1785              : 
    1786              : private:
    1787              :   location_t locus;
    1788              : 
    1789              : public:
    1790              :   // Returns whether struct has generic parameters.
    1791         6276 :   bool has_generics () const { return !generic_params.empty (); }
    1792              : 
    1793              :   // Returns whether struct has a where clause.
    1794       311197 :   bool has_where_clause () const { return !where_clause.is_empty (); }
    1795              : 
    1796        63520 :   location_t get_locus () const override final { return locus; }
    1797              : 
    1798              :   // Invalid if name is empty, so base stripping on that.
    1799           16 :   void mark_for_strip () override { struct_name = {""}; }
    1800        68075 :   bool is_marked_for_strip () const override { return struct_name.empty (); }
    1801              : 
    1802       195408 :   Identifier get_struct_name () const { return struct_name; }
    1803              : 
    1804         3132 :   std::vector<std::unique_ptr<GenericParam>> &get_generic_params ()
    1805              :   {
    1806       311755 :     return generic_params;
    1807              :   }
    1808              :   const std::vector<std::unique_ptr<GenericParam>> &get_generic_params () const
    1809              :   {
    1810              :     return generic_params;
    1811              :   }
    1812              : 
    1813              :   // TODO: is this better? Or is a "vis_block" better?
    1814         3235 :   WhereClause &get_where_clause () { return where_clause; }
    1815              : 
    1816         6898 :   Identifier get_identifier () const { return struct_name; }
    1817              : 
    1818        11719 :   Item::Kind get_item_kind () const override { return Item::Kind::Struct; }
    1819              : 
    1820              : protected:
    1821         4017 :   Struct (Identifier struct_name,
    1822              :           std::vector<std::unique_ptr<GenericParam>> generic_params,
    1823              :           WhereClause where_clause, Visibility vis, location_t locus,
    1824              :           std::vector<Attribute> outer_attrs = std::vector<Attribute> ())
    1825              :     : VisItem (std::move (vis), std::move (outer_attrs)),
    1826         8034 :       struct_name (std::move (struct_name)),
    1827         4017 :       generic_params (std::move (generic_params)),
    1828         4017 :       where_clause (std::move (where_clause)), locus (locus)
    1829         4017 :   {}
    1830              : 
    1831              :   // Copy constructor with vector clone
    1832        11437 :   Struct (Struct const &other)
    1833        11437 :     : VisItem (other), struct_name (other.struct_name),
    1834        11437 :       where_clause (other.where_clause), locus (other.locus)
    1835              :   {
    1836        11437 :     generic_params.reserve (other.generic_params.size ());
    1837        15805 :     for (const auto &e : other.generic_params)
    1838         4368 :       generic_params.push_back (e->clone_generic_param ());
    1839        11437 :   }
    1840              : 
    1841              :   // Overloaded assignment operator with vector clone
    1842              :   Struct &operator= (Struct const &other)
    1843              :   {
    1844              :     VisItem::operator= (other);
    1845              :     struct_name = other.struct_name;
    1846              :     where_clause = other.where_clause;
    1847              :     locus = other.locus;
    1848              : 
    1849              :     generic_params.reserve (other.generic_params.size ());
    1850              :     for (const auto &e : other.generic_params)
    1851              :       generic_params.push_back (e->clone_generic_param ());
    1852              : 
    1853              :     return *this;
    1854              :   }
    1855              : 
    1856              :   // move constructors
    1857              :   Struct (Struct &&other) = default;
    1858              :   Struct &operator= (Struct &&other) = default;
    1859              : };
    1860              : 
    1861              : // A single field in a struct
    1862              : class StructField
    1863              : {
    1864              :   // bool has_outer_attributes;
    1865              :   std::vector<Attribute> outer_attrs;
    1866              : 
    1867              :   // bool has_visibility;
    1868              :   Visibility visibility;
    1869              : 
    1870              :   Identifier field_name;
    1871              :   std::unique_ptr<Type> field_type;
    1872              : 
    1873              :   NodeId node_id;
    1874              : 
    1875              :   location_t locus;
    1876              : 
    1877              : public:
    1878              :   // Returns whether struct field has any outer attributes.
    1879              :   bool has_outer_attributes () const { return !outer_attrs.empty (); }
    1880              : 
    1881              :   // Returns whether struct field has a non-private (non-default) visibility.
    1882              :   bool has_visibility () const { return true; }
    1883              : 
    1884         3391 :   StructField (Identifier field_name, std::unique_ptr<Type> field_type,
    1885              :                Visibility vis, location_t locus,
    1886              :                std::vector<Attribute> outer_attrs = std::vector<Attribute> ())
    1887         3391 :     : outer_attrs (std::move (outer_attrs)), visibility (std::move (vis)),
    1888         3391 :       field_name (std::move (field_name)), field_type (std::move (field_type)),
    1889         3391 :       node_id (Analysis::Mappings::get ().get_next_node_id ()), locus (locus)
    1890         3391 :   {}
    1891              : 
    1892              :   // Copy constructor
    1893         7931 :   StructField (StructField const &other)
    1894         7931 :     : outer_attrs (other.outer_attrs), visibility (other.visibility),
    1895         7931 :       field_name (other.field_name), node_id (other.node_id),
    1896         7931 :       locus (other.locus)
    1897              :   {
    1898              :     // guard to prevent null dereference
    1899         7931 :     if (other.field_type != nullptr)
    1900         7931 :       field_type = other.field_type->clone_type ();
    1901         7931 :   }
    1902              : 
    1903        13103 :   ~StructField () = default;
    1904              : 
    1905              :   // Overloaded assignment operator to clone
    1906              :   StructField &operator= (StructField const &other)
    1907              :   {
    1908              :     field_name = other.field_name;
    1909              :     visibility = other.visibility;
    1910              :     outer_attrs = other.outer_attrs;
    1911              :     node_id = other.node_id;
    1912              : 
    1913              :     // guard to prevent null dereference
    1914              :     if (other.field_type != nullptr)
    1915              :       field_type = other.field_type->clone_type ();
    1916              :     else
    1917              :       field_type = nullptr;
    1918              : 
    1919              :     return *this;
    1920              :   }
    1921              : 
    1922              :   // move constructors
    1923         5079 :   StructField (StructField &&other) = default;
    1924            2 :   StructField &operator= (StructField &&other) = default;
    1925              : 
    1926              :   // Returns whether struct field is in an error state.
    1927         3256 :   bool is_error () const
    1928              :   {
    1929         3256 :     return field_name.empty () && field_type == nullptr;
    1930              :     // this should really be an or since neither are allowed
    1931              :   }
    1932              : 
    1933              :   // Creates an error state struct field.
    1934           59 :   static StructField create_error ()
    1935              :   {
    1936          118 :     return StructField (std::string (""), nullptr,
    1937          177 :                         Visibility::create_private (), UNDEF_LOCATION);
    1938              :   }
    1939              : 
    1940              :   std::string as_string () const;
    1941              : 
    1942              :   // TODO: this mutable getter seems really dodgy. Think up better way.
    1943       193159 :   std::vector<Attribute> &get_outer_attrs () { return outer_attrs; }
    1944              :   const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
    1945              : 
    1946         6279 :   Identifier get_field_name () const { return field_name; }
    1947              : 
    1948         5580 :   location_t get_locus () const { return locus; }
    1949              : 
    1950              :   // TODO: is this better? Or is a "vis_block" better?
    1951       152167 :   Type &get_field_type ()
    1952              :   {
    1953       152167 :     rust_assert (field_type != nullptr);
    1954       152167 :     return *field_type;
    1955              :   }
    1956              : 
    1957        44248 :   std::unique_ptr<Type> &get_field_type_ptr ()
    1958              :   {
    1959        44248 :     rust_assert (field_type != nullptr);
    1960        44248 :     return field_type;
    1961              :   }
    1962              : 
    1963       165474 :   Visibility &get_visibility () { return visibility; }
    1964              :   const Visibility &get_visibility () const { return visibility; }
    1965              : 
    1966         3264 :   NodeId get_node_id () const { return node_id; }
    1967              : };
    1968              : 
    1969              : // Rust struct declaration with true struct type AST node
    1970              : class StructStruct : public Struct
    1971              : {
    1972              :   std::vector<StructField> fields;
    1973              :   bool is_unit;
    1974              : 
    1975              : public:
    1976              :   std::string as_string () const override;
    1977              : 
    1978              :   // Mega-constructor with all possible fields
    1979         1585 :   StructStruct (std::vector<StructField> fields, Identifier struct_name,
    1980              :                 std::vector<std::unique_ptr<GenericParam>> generic_params,
    1981              :                 WhereClause where_clause, bool is_unit, Visibility vis,
    1982              :                 std::vector<Attribute> outer_attrs, location_t locus)
    1983              :     : Struct (std::move (struct_name), std::move (generic_params),
    1984              :               std::move (where_clause), std::move (vis), locus,
    1985              :               std::move (outer_attrs)),
    1986         1585 :       fields (std::move (fields)), is_unit (is_unit)
    1987         1585 :   {}
    1988              : 
    1989              :   // Unit struct constructor
    1990         1239 :   StructStruct (Identifier struct_name,
    1991              :                 std::vector<std::unique_ptr<GenericParam>> generic_params,
    1992              :                 WhereClause where_clause, Visibility vis,
    1993              :                 std::vector<Attribute> outer_attrs, location_t locus)
    1994              :     : Struct (std::move (struct_name), std::move (generic_params),
    1995              :               std::move (where_clause), std::move (vis), locus,
    1996              :               std::move (outer_attrs)),
    1997         1239 :       is_unit (true)
    1998         1239 :   {}
    1999              : 
    2000              :   /* Returns whether the struct is a unit struct - struct defined without
    2001              :    * fields. This is important because it also means an implicit constant of its
    2002              :    * type is defined. */
    2003        31782 :   bool is_unit_struct () const { return is_unit; }
    2004              : 
    2005              :   void accept_vis (ASTVisitor &vis) override;
    2006              : 
    2007              :   // TODO: this mutable getter seems really dodgy. Think up better way.
    2008       380285 :   std::vector<StructField> &get_fields () { return fields; }
    2009              :   const std::vector<StructField> &get_fields () const { return fields; }
    2010              : 
    2011              : protected:
    2012              :   /* Use covariance to implement clone function as returning this object
    2013              :    * rather than base */
    2014         5882 :   StructStruct *clone_item_impl () const override
    2015              :   {
    2016         5882 :     return new StructStruct (*this);
    2017              :   }
    2018              : };
    2019              : 
    2020              : // A single field in a tuple
    2021              : class TupleField
    2022              : {
    2023              :   // bool has_outer_attributes;
    2024              :   std::vector<Attribute> outer_attrs;
    2025              : 
    2026              :   // bool has_visibility;
    2027              :   Visibility visibility;
    2028              : 
    2029              :   std::unique_ptr<Type> field_type;
    2030              : 
    2031              :   NodeId node_id;
    2032              : 
    2033              :   location_t locus;
    2034              : 
    2035              : public:
    2036              :   // Returns whether tuple field has outer attributes.
    2037              :   bool has_outer_attributes () const { return !outer_attrs.empty (); }
    2038              : 
    2039              :   /* Returns whether tuple field has a non-default visibility (i.e. a public
    2040              :    * one) */
    2041              :   bool has_visibility () const { return true; }
    2042              : 
    2043              :   // Complete constructor
    2044         2944 :   TupleField (std::unique_ptr<Type> field_type, Visibility vis,
    2045              :               location_t locus,
    2046              :               std::vector<Attribute> outer_attrs = std::vector<Attribute> ())
    2047         2944 :     : outer_attrs (std::move (outer_attrs)), visibility (std::move (vis)),
    2048         2944 :       field_type (std::move (field_type)),
    2049         2944 :       node_id (Analysis::Mappings::get ().get_next_node_id ()), locus (locus)
    2050         2944 :   {}
    2051              : 
    2052              :   // Copy constructor with clone
    2053         8684 :   TupleField (TupleField const &other)
    2054         8684 :     : outer_attrs (other.outer_attrs), visibility (other.visibility),
    2055         8684 :       node_id (other.node_id), locus (other.locus)
    2056              :   {
    2057              :     // guard to prevent null dereference (only required if error)
    2058         8684 :     if (other.field_type != nullptr)
    2059         8684 :       field_type = other.field_type->clone_type ();
    2060         8684 :   }
    2061              : 
    2062        12998 :   ~TupleField () = default;
    2063              : 
    2064              :   // Overloaded assignment operator to clone
    2065              :   TupleField &operator= (TupleField const &other)
    2066              :   {
    2067              :     visibility = other.visibility;
    2068              :     outer_attrs = other.outer_attrs;
    2069              :     node_id = other.node_id;
    2070              :     locus = other.locus;
    2071              : 
    2072              :     // guard to prevent null dereference (only required if error)
    2073              :     if (other.field_type != nullptr)
    2074              :       field_type = other.field_type->clone_type ();
    2075              :     else
    2076              :       field_type = nullptr;
    2077              : 
    2078              :     return *this;
    2079              :   }
    2080              : 
    2081              :   // move constructors
    2082         4298 :   TupleField (TupleField &&other) = default;
    2083            0 :   TupleField &operator= (TupleField &&other) = default;
    2084              : 
    2085              :   // Returns whether tuple field is in an error state.
    2086         2944 :   bool is_error () const { return field_type == nullptr; }
    2087              : 
    2088              :   // Creates an error state tuple field.
    2089            1 :   static TupleField create_error ()
    2090              :   {
    2091            1 :     return TupleField (nullptr, Visibility::create_private (), UNDEF_LOCATION);
    2092              :   }
    2093              : 
    2094              :   std::string as_string () const;
    2095              : 
    2096         2863 :   NodeId get_node_id () const { return node_id; }
    2097              : 
    2098       164718 :   Visibility &get_visibility () { return visibility; }
    2099              :   const Visibility &get_visibility () const { return visibility; }
    2100              : 
    2101         2863 :   location_t get_locus () const { return locus; }
    2102              : 
    2103              :   // TODO: this mutable getter seems really dodgy. Think up better way.
    2104       191920 :   std::vector<Attribute> &get_outer_attrs () { return outer_attrs; }
    2105              :   const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
    2106              : 
    2107              :   // TODO: is this better? Or is a "vis_block" better?
    2108       146430 :   Type &get_field_type ()
    2109              :   {
    2110       146430 :     rust_assert (field_type != nullptr);
    2111       146430 :     return *field_type;
    2112              :   }
    2113              : 
    2114        47849 :   std::unique_ptr<Type> &get_field_type_ptr ()
    2115              :   {
    2116        47849 :     rust_assert (field_type != nullptr);
    2117        47849 :     return field_type;
    2118              :   }
    2119              : };
    2120              : 
    2121              : // Rust tuple declared using struct keyword AST node
    2122              : class TupleStruct : public Struct
    2123              : {
    2124              :   std::vector<TupleField> fields;
    2125              : 
    2126              : public:
    2127              :   std::string as_string () const override;
    2128              : 
    2129              :   // Mega-constructor with all possible fields
    2130         1193 :   TupleStruct (std::vector<TupleField> fields, Identifier struct_name,
    2131              :                std::vector<std::unique_ptr<GenericParam>> generic_params,
    2132              :                WhereClause where_clause, Visibility vis,
    2133              :                std::vector<Attribute> outer_attrs, location_t locus)
    2134              :     : Struct (std::move (struct_name), std::move (generic_params),
    2135              :               std::move (where_clause), std::move (vis), locus,
    2136              :               std::move (outer_attrs)),
    2137         1193 :       fields (std::move (fields))
    2138         1193 :   {}
    2139              : 
    2140              :   void accept_vis (ASTVisitor &vis) override;
    2141              : 
    2142              :   // TODO: this mutable getter seems really dodgy. Think up better way.
    2143        54899 :   std::vector<TupleField> &get_fields () { return fields; }
    2144              :   const std::vector<TupleField> &get_fields () const { return fields; }
    2145              : 
    2146              : protected:
    2147              :   /* Use covariance to implement clone function as returning this object
    2148              :    * rather than base */
    2149         1728 :   TupleStruct *clone_item_impl () const override
    2150              :   {
    2151         1728 :     return new TupleStruct (*this);
    2152              :   }
    2153              : };
    2154              : 
    2155              : /* An item used in an "enum" tagged union - not abstract: base represents a
    2156              :  * name-only enum. EnumItems (variants) syntactically allow a Visibility
    2157              :  * annotation. */
    2158              : class EnumItem : public VisItem
    2159              : {
    2160              :   Identifier variant_name;
    2161              : 
    2162              :   location_t locus;
    2163              : 
    2164              : public:
    2165              :   enum class Kind
    2166              :   {
    2167              :     Identifier,
    2168              :     Tuple,
    2169              :     Struct,
    2170              : 
    2171              :     // FIXME: In the future, we'll need to remove this possibility as well as
    2172              :     // remove the EnumItemDiscriminant class. The feature for arbitrary
    2173              :     // discriminants on all kinds of variants has been stabilized, and a
    2174              :     // "discriminant" is no longer an enum item variant - it's simply an
    2175              :     // optional part of all variants.
    2176              :     //
    2177              :     // Per the reference:
    2178              :     //
    2179              :     // EnumItem :
    2180              :     //    OuterAttribute* Visibility?
    2181              :     //    IDENTIFIER ( EnumItemTuple | EnumItemStruct )? EnumItemDiscriminant?
    2182              :     //
    2183              :     // EnumItemTuple :
    2184              :     //    ( TupleFields? )
    2185              :     //
    2186              :     // EnumItemStruct :
    2187              :     //    { StructFields? }
    2188              :     //
    2189              :     // EnumItemDiscriminant :
    2190              :     //    = Expression
    2191              :     //
    2192              :     // So we instead need to remove the class, and add an optional expression to
    2193              :     // the base EnumItem class
    2194              :     //
    2195              :     // gccrs#3340
    2196              : 
    2197              :     Discriminant,
    2198              :   };
    2199              : 
    2200         5541 :   virtual ~EnumItem () {}
    2201              : 
    2202         1550 :   EnumItem (Identifier variant_name, Visibility vis,
    2203              :             std::vector<Attribute> outer_attrs, location_t locus)
    2204              :     : VisItem (std::move (vis), std::move (outer_attrs)),
    2205         1550 :       variant_name (std::move (variant_name)), locus (locus)
    2206         1550 :   {}
    2207              : 
    2208          249 :   virtual Kind get_enum_item_kind () const { return Kind::Identifier; }
    2209              : 
    2210              :   // Unique pointer custom clone function
    2211         4078 :   std::unique_ptr<EnumItem> clone_enum_item () const
    2212              :   {
    2213         4078 :     return std::unique_ptr<EnumItem> (clone_item_impl ());
    2214              :   }
    2215              : 
    2216              :   virtual std::string as_string () const override;
    2217              : 
    2218              :   // not pure virtual as not abstract
    2219              :   virtual void accept_vis (ASTVisitor &vis) override;
    2220              : 
    2221        10981 :   location_t get_locus () const override { return locus; }
    2222              : 
    2223        27864 :   Identifier get_identifier () const { return variant_name; }
    2224              : 
    2225              :   // Based on idea that name is never empty.
    2226            0 :   void mark_for_strip () override { variant_name = {""}; }
    2227         8282 :   bool is_marked_for_strip () const override { return variant_name.empty (); }
    2228              : 
    2229            0 :   Item::Kind get_item_kind () const override { return Item::Kind::EnumItem; }
    2230              : 
    2231              : protected:
    2232         1457 :   EnumItem *clone_item_impl () const override { return new EnumItem (*this); }
    2233              : };
    2234              : 
    2235              : // A tuple item used in an "enum" tagged union
    2236              : class EnumItemTuple : public EnumItem
    2237              : {
    2238              :   // bool has_tuple_fields;
    2239              :   std::vector<TupleField> tuple_fields;
    2240              : 
    2241              : public:
    2242              :   // Returns whether tuple enum item has tuple fields.
    2243            0 :   bool has_tuple_fields () const { return !tuple_fields.empty (); }
    2244              : 
    2245          558 :   EnumItemTuple (Identifier variant_name, Visibility vis,
    2246              :                  std::vector<TupleField> tuple_fields,
    2247              :                  std::vector<Attribute> outer_attrs, location_t locus)
    2248              :     : EnumItem (std::move (variant_name), std::move (vis),
    2249              :                 std::move (outer_attrs), locus),
    2250          558 :       tuple_fields (std::move (tuple_fields))
    2251          558 :   {}
    2252              : 
    2253          187 :   EnumItem::Kind get_enum_item_kind () const override
    2254              :   {
    2255          187 :     return EnumItem::Kind::Tuple;
    2256              :   }
    2257              : 
    2258              :   std::string as_string () const override;
    2259              : 
    2260              :   void accept_vis (ASTVisitor &vis) override;
    2261              : 
    2262              :   // TODO: this mutable getter seems really dodgy. Think up better way.
    2263        22404 :   std::vector<TupleField> &get_tuple_fields () { return tuple_fields; }
    2264              :   const std::vector<TupleField> &get_tuple_fields () const
    2265              :   {
    2266              :     return tuple_fields;
    2267              :   }
    2268              : 
    2269              : protected:
    2270              :   // Clone function implementation as (not pure) virtual method
    2271         1448 :   EnumItemTuple *clone_item_impl () const override
    2272              :   {
    2273         1448 :     return new EnumItemTuple (*this);
    2274              :   }
    2275              : };
    2276              : 
    2277              : // A struct item used in an "enum" tagged union
    2278              : class EnumItemStruct : public EnumItem
    2279              : {
    2280              :   // bool has_struct_fields;
    2281              :   std::vector<StructField> struct_fields;
    2282              : 
    2283              : public:
    2284              :   // Returns whether struct enum item has struct fields.
    2285            0 :   bool has_struct_fields () const { return !struct_fields.empty (); }
    2286              : 
    2287          100 :   EnumItemStruct (Identifier variant_name, Visibility vis,
    2288              :                   std::vector<StructField> struct_fields,
    2289              :                   std::vector<Attribute> outer_attrs, location_t locus)
    2290              :     : EnumItem (std::move (variant_name), std::move (vis),
    2291              :                 std::move (outer_attrs), locus),
    2292          100 :       struct_fields (std::move (struct_fields))
    2293          100 :   {}
    2294              : 
    2295           36 :   EnumItem::Kind get_enum_item_kind () const override
    2296              :   {
    2297           36 :     return EnumItem::Kind::Struct;
    2298              :   }
    2299              : 
    2300              :   std::string as_string () const override;
    2301              : 
    2302              :   void accept_vis (ASTVisitor &vis) override;
    2303              : 
    2304              :   // TODO: this mutable getter seems really dodgy. Think up better way.
    2305         2716 :   std::vector<StructField> &get_struct_fields () { return struct_fields; }
    2306              :   const std::vector<StructField> &get_struct_fields () const
    2307              :   {
    2308           11 :     return struct_fields;
    2309              :   }
    2310              : 
    2311              : protected:
    2312              :   // Clone function implementation as (not pure) virtual method
    2313          208 :   EnumItemStruct *clone_item_impl () const override
    2314              :   {
    2315          208 :     return new EnumItemStruct (*this);
    2316              :   }
    2317              : };
    2318              : 
    2319              : // A discriminant (numbered enum) item used in an "enum" tagged union
    2320              : class EnumItemDiscriminant : public EnumItem
    2321              : {
    2322              :   std::unique_ptr<Expr> expression;
    2323              : 
    2324              : public:
    2325          296 :   EnumItemDiscriminant (Identifier variant_name, Visibility vis,
    2326              :                         std::unique_ptr<Expr> expr,
    2327              :                         std::vector<Attribute> outer_attrs, location_t locus)
    2328              :     : EnumItem (std::move (variant_name), std::move (vis),
    2329              :                 std::move (outer_attrs), locus),
    2330          296 :       expression (std::move (expr))
    2331          296 :   {}
    2332              : 
    2333              :   // Copy constructor with clone
    2334          965 :   EnumItemDiscriminant (EnumItemDiscriminant const &other)
    2335          965 :     : EnumItem (other), expression (other.expression->clone_expr ())
    2336          965 :   {}
    2337              : 
    2338              :   // Overloaded assignment operator to clone
    2339              :   EnumItemDiscriminant &operator= (EnumItemDiscriminant const &other)
    2340              :   {
    2341              :     EnumItem::operator= (other);
    2342              :     expression = other.expression->clone_expr ();
    2343              :     // variant_name = other.variant_name;
    2344              :     // outer_attrs = other.outer_attrs;
    2345              : 
    2346              :     return *this;
    2347              :   }
    2348              : 
    2349              :   // move constructors
    2350              :   EnumItemDiscriminant (EnumItemDiscriminant &&other) = default;
    2351              :   EnumItemDiscriminant &operator= (EnumItemDiscriminant &&other) = default;
    2352              : 
    2353           18 :   EnumItem::Kind get_enum_item_kind () const override
    2354              :   {
    2355           18 :     return EnumItem::Kind::Discriminant;
    2356              :   }
    2357              : 
    2358              :   std::string as_string () const override;
    2359              : 
    2360              :   void accept_vis (ASTVisitor &vis) override;
    2361              : 
    2362              :   bool has_expr () { return expression != nullptr; }
    2363              : 
    2364              :   // TODO: is this better? Or is a "vis_block" better?
    2365         8747 :   Expr &get_expr ()
    2366              :   {
    2367         8747 :     rust_assert (expression != nullptr);
    2368         8747 :     return *expression;
    2369              :   }
    2370              : 
    2371         1934 :   std::unique_ptr<Expr> &get_expr_ptr ()
    2372              :   {
    2373         1934 :     rust_assert (expression != nullptr);
    2374         1934 :     return expression;
    2375              :   }
    2376              : 
    2377              : protected:
    2378              :   // Clone function implementation as (not pure) virtual method
    2379          965 :   EnumItemDiscriminant *clone_item_impl () const override
    2380              :   {
    2381          965 :     return new EnumItemDiscriminant (*this);
    2382              :   }
    2383              : };
    2384              : 
    2385              : // AST node for Rust "enum" - tagged union
    2386              : class Enum : public VisItem, public GlobContainer
    2387              : {
    2388              :   Identifier enum_name;
    2389              : 
    2390              :   // bool has_generics;
    2391              :   // Generics generic_params;
    2392              :   std::vector<std::unique_ptr<GenericParam>> generic_params; // inlined
    2393              : 
    2394              :   // bool has_where_clause;
    2395              :   WhereClause where_clause;
    2396              : 
    2397              :   std::vector<std::unique_ptr<EnumItem>> items;
    2398              : 
    2399              :   location_t locus;
    2400              : 
    2401              : public:
    2402              :   std::string as_string () const override;
    2403              : 
    2404              :   // Returns whether "enum" has generic parameters.
    2405         1170 :   bool has_generics () const { return !generic_params.empty (); }
    2406              : 
    2407              :   // Returns whether "enum" has a where clause.
    2408        22233 :   bool has_where_clause () const { return !where_clause.is_empty (); }
    2409              : 
    2410              :   /* Returns whether enum is a "zero-variant" (no possible variant) enum,
    2411              :    * which cannot be instantiated. */
    2412              :   bool is_zero_variant () const { return items.empty (); }
    2413              : 
    2414              :   // Mega-constructor
    2415          668 :   Enum (Identifier enum_name, Visibility vis,
    2416              :         std::vector<std::unique_ptr<GenericParam>> generic_params,
    2417              :         WhereClause where_clause, std::vector<std::unique_ptr<EnumItem>> items,
    2418              :         std::vector<Attribute> outer_attrs, location_t locus)
    2419              :     : VisItem (std::move (vis), std::move (outer_attrs)),
    2420          668 :       enum_name (std::move (enum_name)),
    2421          668 :       generic_params (std::move (generic_params)),
    2422          668 :       where_clause (std::move (where_clause)), items (std::move (items)),
    2423          668 :       locus (locus)
    2424          668 :   {}
    2425              : 
    2426              :   // TODO: constructor with less arguments
    2427              : 
    2428              :   // Copy constructor with vector clone
    2429         1756 :   Enum (Enum const &other)
    2430         1756 :     : VisItem (other), enum_name (other.enum_name),
    2431         1756 :       where_clause (other.where_clause), locus (other.locus)
    2432              :   {
    2433         1756 :     generic_params.reserve (other.generic_params.size ());
    2434         2775 :     for (const auto &e : other.generic_params)
    2435         1019 :       generic_params.push_back (e->clone_generic_param ());
    2436              : 
    2437         1756 :     items.reserve (other.items.size ());
    2438         5834 :     for (const auto &e : other.items)
    2439         4078 :       items.push_back (e->clone_enum_item ());
    2440         1756 :   }
    2441              : 
    2442              :   // Overloaded assignment operator with vector clone
    2443              :   Enum &operator= (Enum const &other)
    2444              :   {
    2445              :     VisItem::operator= (other);
    2446              :     enum_name = other.enum_name;
    2447              :     where_clause = other.where_clause;
    2448              :     locus = other.locus;
    2449              : 
    2450              :     generic_params.reserve (other.generic_params.size ());
    2451              :     for (const auto &e : other.generic_params)
    2452              :       generic_params.push_back (e->clone_generic_param ());
    2453              : 
    2454              :     items.reserve (other.items.size ());
    2455              :     for (const auto &e : other.items)
    2456              :       items.push_back (e->clone_enum_item ());
    2457              : 
    2458              :     return *this;
    2459              :   }
    2460              : 
    2461              :   // Move constructors
    2462              :   Enum (Enum &&other) = default;
    2463              :   Enum &operator= (Enum &&other) = default;
    2464              : 
    2465         5198 :   location_t get_locus () const override final { return locus; }
    2466              : 
    2467              :   void accept_vis (ASTVisitor &vis) override;
    2468              : 
    2469        17993 :   Identifier get_identifier () const { return enum_name; }
    2470              : 
    2471              :   // Invalid if name is empty, so base stripping on that.
    2472            0 :   void mark_for_strip () override { enum_name = {""}; }
    2473         2639 :   bool is_marked_for_strip () const override { return enum_name.empty (); }
    2474              : 
    2475              :   // TODO: this mutable getter seems really dodgy. Think up better way.
    2476        25725 :   std::vector<std::unique_ptr<EnumItem>> &get_variants () { return items; }
    2477              :   const std::vector<std::unique_ptr<EnumItem>> &get_variants () const
    2478              :   {
    2479              :     return items;
    2480              :   }
    2481              : 
    2482          755 :   std::vector<std::unique_ptr<GenericParam>> &get_generic_params ()
    2483              :   {
    2484        22460 :     return generic_params;
    2485              :   }
    2486              :   const std::vector<std::unique_ptr<GenericParam>> &get_generic_params () const
    2487              :   {
    2488              :     return generic_params;
    2489              :   }
    2490              : 
    2491              :   // TODO: is this better? Or is a "vis_block" better?
    2492           32 :   WhereClause &get_where_clause () { return where_clause; }
    2493              : 
    2494         1092 :   Item::Kind get_item_kind () const override { return Item::Kind::Enum; }
    2495              : 
    2496         1395 :   GlobContainer::Kind get_glob_container_kind () const override
    2497              :   {
    2498         1395 :     return GlobContainer::Kind::Enum;
    2499              :   }
    2500              : 
    2501              : protected:
    2502              :   /* Use covariance to implement clone function as returning this object
    2503              :    * rather than base */
    2504         1091 :   Enum *clone_item_impl () const override { return new Enum (*this); }
    2505              : };
    2506              : 
    2507              : // Rust untagged union used for C compat AST node
    2508              : class Union : public VisItem
    2509              : {
    2510              :   Identifier union_name;
    2511              : 
    2512              :   // bool has_generics;
    2513              :   // Generics generic_params;
    2514              :   std::vector<std::unique_ptr<GenericParam>> generic_params; // inlined
    2515              : 
    2516              :   // bool has_where_clause;
    2517              :   WhereClause where_clause;
    2518              : 
    2519              :   std::vector<StructField> variants;
    2520              : 
    2521              :   location_t locus;
    2522              : 
    2523              : public:
    2524              :   std::string as_string () const override;
    2525              : 
    2526              :   // Returns whether union has generic params.
    2527          212 :   bool has_generics () const { return !generic_params.empty (); }
    2528              : 
    2529              :   // Returns whether union has where clause.
    2530         2978 :   bool has_where_clause () const { return !where_clause.is_empty (); }
    2531              : 
    2532          116 :   Union (Identifier union_name, Visibility vis,
    2533              :          std::vector<std::unique_ptr<GenericParam>> generic_params,
    2534              :          WhereClause where_clause, std::vector<StructField> variants,
    2535              :          std::vector<Attribute> outer_attrs, location_t locus)
    2536              :     : VisItem (std::move (vis), std::move (outer_attrs)),
    2537          232 :       union_name (std::move (union_name)),
    2538          116 :       generic_params (std::move (generic_params)),
    2539          116 :       where_clause (std::move (where_clause)), variants (std::move (variants)),
    2540          116 :       locus (locus)
    2541          116 :   {}
    2542              : 
    2543              :   // copy constructor with vector clone
    2544          242 :   Union (Union const &other)
    2545          242 :     : VisItem (other), union_name (other.union_name),
    2546          242 :       where_clause (other.where_clause), variants (other.variants),
    2547          242 :       locus (other.locus)
    2548              :   {
    2549          242 :     generic_params.reserve (other.generic_params.size ());
    2550          415 :     for (const auto &e : other.generic_params)
    2551          173 :       generic_params.push_back (e->clone_generic_param ());
    2552          242 :   }
    2553              : 
    2554              :   // overloaded assignment operator with vector clone
    2555              :   Union &operator= (Union const &other)
    2556              :   {
    2557              :     VisItem::operator= (other);
    2558              :     union_name = other.union_name;
    2559              :     where_clause = other.where_clause;
    2560              :     variants = other.variants;
    2561              :     locus = other.locus;
    2562              : 
    2563              :     generic_params.reserve (other.generic_params.size ());
    2564              :     for (const auto &e : other.generic_params)
    2565              :       generic_params.push_back (e->clone_generic_param ());
    2566              : 
    2567              :     return *this;
    2568              :   }
    2569              : 
    2570              :   // move constructors
    2571              :   Union (Union &&other) = default;
    2572              :   Union &operator= (Union &&other) = default;
    2573              : 
    2574          659 :   location_t get_locus () const override final { return locus; }
    2575              : 
    2576              :   void accept_vis (ASTVisitor &vis) override;
    2577              : 
    2578              :   // Invalid if name is empty, so base stripping on that.
    2579            0 :   void mark_for_strip () override { union_name = {""}; }
    2580          308 :   bool is_marked_for_strip () const override { return union_name.empty (); }
    2581              : 
    2582              :   // TODO: this mutable getter seems really dodgy. Think up better way.
    2583         3515 :   std::vector<StructField> &get_variants () { return variants; }
    2584              :   const std::vector<StructField> &get_variants () const { return variants; }
    2585              : 
    2586          157 :   std::vector<std::unique_ptr<GenericParam>> &get_generic_params ()
    2587              :   {
    2588         3034 :     return generic_params;
    2589              :   }
    2590              :   const std::vector<std::unique_ptr<GenericParam>> &get_generic_params () const
    2591              :   {
    2592              :     return generic_params;
    2593              :   }
    2594              : 
    2595              :   // TODO: is this better? Or is a "vis_block" better?
    2596            0 :   WhereClause &get_where_clause () { return where_clause; }
    2597              : 
    2598         2327 :   Identifier get_identifier () const { return union_name; }
    2599              : 
    2600          500 :   Item::Kind get_item_kind () const override { return Item::Kind::Union; }
    2601              : 
    2602              : protected:
    2603              :   /* Use covariance to implement clone function as returning this object
    2604              :    * rather than base */
    2605          126 :   Union *clone_item_impl () const override { return new Union (*this); }
    2606              : };
    2607              : 
    2608              : /* "Constant item" AST node - used for constant, compile-time expressions
    2609              :  * within module scope (like constexpr) */
    2610              : class ConstantItem : public VisItem, public AssociatedItem
    2611              : {
    2612              :   // either has an identifier or "_" - maybe handle in identifier?
    2613              :   // bool identifier_is_underscore;
    2614              :   // if no identifier declared, identifier will be "_"
    2615              :   Identifier identifier;
    2616              : 
    2617              :   std::unique_ptr<Type> type;
    2618              :   std::unique_ptr<Expr> const_expr;
    2619              : 
    2620              :   location_t locus;
    2621              : 
    2622              : public:
    2623              :   std::string as_string () const override;
    2624              : 
    2625         1367 :   ConstantItem (Identifier ident, Visibility vis, std::unique_ptr<Type> type,
    2626              :                 std::unique_ptr<Expr> const_expr,
    2627              :                 std::vector<Attribute> outer_attrs, location_t locus)
    2628              :     : VisItem (std::move (vis), std::move (outer_attrs)),
    2629         1367 :       identifier (std::move (ident)), type (std::move (type)),
    2630         1367 :       const_expr (std::move (const_expr)), locus (locus)
    2631         1367 :   {}
    2632              : 
    2633            4 :   ConstantItem (Identifier ident, Visibility vis, std::unique_ptr<Type> type,
    2634              :                 std::vector<Attribute> outer_attrs, location_t locus)
    2635              :     : VisItem (std::move (vis), std::move (outer_attrs)),
    2636            4 :       identifier (std::move (ident)), type (std::move (type)),
    2637            4 :       const_expr (nullptr), locus (locus)
    2638            4 :   {}
    2639              : 
    2640         4535 :   ConstantItem (ConstantItem const &other)
    2641         4535 :     : VisItem (other), identifier (other.identifier), locus (other.locus)
    2642              :   {
    2643              :     // guard to prevent null dereference (only required if error state)
    2644         4535 :     if (other.type != nullptr)
    2645         4535 :       type = other.type->clone_type ();
    2646         4535 :     if (other.const_expr != nullptr)
    2647         4341 :       const_expr = other.const_expr->clone_expr ();
    2648         4535 :   }
    2649              : 
    2650              :   // Overload assignment operator to clone
    2651              :   ConstantItem &operator= (ConstantItem const &other)
    2652              :   {
    2653              :     VisItem::operator= (other);
    2654              :     identifier = other.identifier;
    2655              :     locus = other.locus;
    2656              : 
    2657              :     // guard to prevent null dereference (only required if error state)
    2658              :     if (other.type != nullptr)
    2659              :       type = other.type->clone_type ();
    2660              :     else
    2661              :       type = nullptr;
    2662              :     if (other.const_expr != nullptr)
    2663              :       const_expr = other.const_expr->clone_expr ();
    2664              :     else
    2665              :       const_expr = nullptr;
    2666              : 
    2667              :     return *this;
    2668              :   }
    2669              : 
    2670              :   // move constructors
    2671              :   ConstantItem (ConstantItem &&other) = default;
    2672              :   ConstantItem &operator= (ConstantItem &&other) = default;
    2673              : 
    2674              :   /* Returns whether constant item is an "unnamed" (wildcard underscore used
    2675              :    * as identifier) constant. */
    2676          552 :   bool is_unnamed () const { return identifier.as_string () == "_"; }
    2677              : 
    2678        29091 :   location_t get_locus () const override final { return locus; }
    2679              : 
    2680              :   // needed to override AssociatedItem::get_node_id
    2681       110538 :   NodeId get_node_id () const override final { return VisItem::get_node_id (); }
    2682              : 
    2683              :   void accept_vis (ASTVisitor &vis) override;
    2684              : 
    2685              :   // Invalid if type and expression are null, so base stripping on that.
    2686            1 :   void mark_for_strip () override
    2687              :   {
    2688            1 :     type = nullptr;
    2689            1 :     const_expr = nullptr;
    2690            1 :   }
    2691        26573 :   bool is_marked_for_strip () const override
    2692              :   {
    2693        26573 :     return type == nullptr && const_expr == nullptr;
    2694              :   }
    2695              : 
    2696       210875 :   bool has_expr () const { return const_expr != nullptr; }
    2697              : 
    2698              :   // TODO: is this better? Or is a "vis_block" better?
    2699       151222 :   Expr &get_expr ()
    2700              :   {
    2701       151222 :     rust_assert (const_expr != nullptr);
    2702       151222 :     return *const_expr;
    2703              :   }
    2704              : 
    2705        51338 :   std::unique_ptr<Expr> &get_expr_ptr ()
    2706              :   {
    2707        51338 :     rust_assert (const_expr != nullptr);
    2708        51338 :     return const_expr;
    2709              :   }
    2710              : 
    2711              :   // TODO: is this better? Or is a "vis_block" better?
    2712       156867 :   Type &get_type ()
    2713              :   {
    2714       156867 :     rust_assert (type != nullptr);
    2715       156867 :     return *type;
    2716              :   }
    2717              : 
    2718        52866 :   std::unique_ptr<Type> &get_type_ptr ()
    2719              :   {
    2720        52866 :     rust_assert (type != nullptr);
    2721        52866 :     return type;
    2722              :   }
    2723              : 
    2724        83202 :   const Identifier &get_identifier () const { return identifier; }
    2725              : 
    2726         2231 :   Item::Kind get_item_kind () const override
    2727              :   {
    2728         2231 :     return Item::Kind::ConstantItem;
    2729              :   }
    2730              : 
    2731              : protected:
    2732              :   /* Use covariance to implement clone function as returning this object
    2733              :    * rather than base */
    2734         2094 :   ConstantItem *clone_item_impl () const override
    2735              :   {
    2736         2094 :     return new ConstantItem (*this);
    2737              :   }
    2738              : 
    2739              :   /* Use covariance to implement clone function as returning this object
    2740              :    * rather than base */
    2741         1084 :   ConstantItem *clone_associated_item_impl () const override
    2742              :   {
    2743         1084 :     return new ConstantItem (*this);
    2744              :   }
    2745              : };
    2746              : 
    2747              : /* Static item AST node - items within module scope with fixed storage
    2748              :  * duration? */
    2749              : class StaticItem : public VisItem
    2750              : {
    2751              :   bool has_mut;
    2752              :   Identifier name;
    2753              :   std::unique_ptr<Type> type;
    2754              :   std::unique_ptr<Expr> expr;
    2755              :   location_t locus;
    2756              : 
    2757              : public:
    2758              :   std::string as_string () const override;
    2759              : 
    2760          133 :   StaticItem (Identifier name, bool is_mut, std::unique_ptr<Type> type,
    2761              :               std::unique_ptr<Expr> expr, Visibility vis,
    2762              :               std::vector<Attribute> outer_attrs, location_t locus)
    2763          133 :     : VisItem (std::move (vis), std::move (outer_attrs)), has_mut (is_mut),
    2764          266 :       name (std::move (name)), type (std::move (type)), expr (std::move (expr)),
    2765          133 :       locus (locus)
    2766          133 :   {}
    2767              : 
    2768              :   // Copy constructor with clone
    2769          204 :   StaticItem (StaticItem const &other)
    2770          204 :     : VisItem (other), has_mut (other.has_mut), name (other.name),
    2771          204 :       locus (other.locus)
    2772              :   {
    2773              :     // guard to prevent null dereference (only required if error state)
    2774          204 :     if (other.type != nullptr)
    2775          204 :       type = other.type->clone_type ();
    2776          204 :     if (other.expr != nullptr)
    2777          204 :       expr = other.expr->clone_expr ();
    2778          204 :   }
    2779              : 
    2780              :   // Overloaded assignment operator to clone
    2781              :   StaticItem &operator= (StaticItem const &other)
    2782              :   {
    2783              :     VisItem::operator= (other);
    2784              :     name = other.name;
    2785              :     has_mut = other.has_mut;
    2786              :     locus = other.locus;
    2787              : 
    2788              :     // guard to prevent null dereference (only required if error state)
    2789              :     if (other.type != nullptr)
    2790              :       type = other.type->clone_type ();
    2791              :     else
    2792              :       type = nullptr;
    2793              :     if (other.expr != nullptr)
    2794              :       expr = other.expr->clone_expr ();
    2795              :     else
    2796              :       expr = nullptr;
    2797              : 
    2798              :     return *this;
    2799              :   }
    2800              : 
    2801              :   // move constructors
    2802              :   StaticItem (StaticItem &&other) = default;
    2803              :   StaticItem &operator= (StaticItem &&other) = default;
    2804              : 
    2805         1753 :   location_t get_locus () const override final { return locus; }
    2806              : 
    2807              :   void accept_vis (ASTVisitor &vis) override;
    2808              : 
    2809              :   // Invalid if type or expression are null, so base stripping on that.
    2810            0 :   void mark_for_strip () override
    2811              :   {
    2812            0 :     type = nullptr;
    2813            0 :     expr = nullptr;
    2814            0 :   }
    2815         1415 :   bool is_marked_for_strip () const override
    2816              :   {
    2817         1415 :     return type == nullptr && expr == nullptr;
    2818              :   }
    2819              : 
    2820           70 :   bool has_expr () { return expr != nullptr; }
    2821              : 
    2822              :   // TODO: is this better? Or is a "vis_block" better?
    2823         8270 :   Expr &get_expr ()
    2824              :   {
    2825         8270 :     rust_assert (expr != nullptr);
    2826         8270 :     return *expr;
    2827              :   }
    2828              : 
    2829         2954 :   std::unique_ptr<Expr> &get_expr_ptr ()
    2830              :   {
    2831         2954 :     rust_assert (expr != nullptr);
    2832         2954 :     return expr;
    2833              :   }
    2834              : 
    2835              :   // TODO: is this better? Or is a "vis_block" better?
    2836         8270 :   Type &get_type ()
    2837              :   {
    2838         8270 :     rust_assert (type != nullptr);
    2839         8270 :     return *type;
    2840              :   }
    2841              : 
    2842         2954 :   std::unique_ptr<Type> &get_type_ptr ()
    2843              :   {
    2844         2954 :     rust_assert (type != nullptr);
    2845         2954 :     return type;
    2846              :   }
    2847              : 
    2848          181 :   bool is_mutable () const { return has_mut; }
    2849              : 
    2850         4812 :   Identifier get_identifier () const { return name; }
    2851              : 
    2852           49 :   Item::Kind get_item_kind () const override { return Item::Kind::StaticItem; }
    2853              : 
    2854              : protected:
    2855              :   /* Use covariance to implement clone function as returning this object
    2856              :    * rather than base */
    2857          204 :   StaticItem *clone_item_impl () const override
    2858              :   {
    2859          204 :     return new StaticItem (*this);
    2860              :   }
    2861              : };
    2862              : 
    2863              : // Type items within traits
    2864              : class TraitItemType : public TraitItem
    2865              : {
    2866              :   std::vector<Attribute> outer_attrs;
    2867              : 
    2868              :   Identifier name;
    2869              : 
    2870              :   // Generic parameters for GATs (Generic Associated Types)
    2871              :   std::vector<std::unique_ptr<GenericParam>> generic_params;
    2872              : 
    2873              :   // bool has_type_param_bounds;
    2874              :   // TypeParamBounds type_param_bounds;
    2875              :   std::vector<std::unique_ptr<TypeParamBound>>
    2876              :     type_param_bounds; // inlined form
    2877              : 
    2878              : public:
    2879            0 :   bool has_generics () const { return !generic_params.empty (); }
    2880              : 
    2881              :   // Returns whether trait item type has type param bounds.
    2882            0 :   bool has_type_param_bounds () const { return !type_param_bounds.empty (); }
    2883              : 
    2884          911 :   TraitItemType (Identifier name,
    2885              :                  std::vector<std::unique_ptr<GenericParam>> generic_params,
    2886              :                  std::vector<std::unique_ptr<TypeParamBound>> type_param_bounds,
    2887              :                  std::vector<Attribute> outer_attrs, Visibility vis,
    2888              :                  location_t locus)
    2889          911 :     : TraitItem (vis, locus), outer_attrs (std::move (outer_attrs)),
    2890          911 :       name (std::move (name)), generic_params (std::move (generic_params)),
    2891          911 :       type_param_bounds (std::move (type_param_bounds))
    2892          911 :   {}
    2893              : 
    2894              :   // Copy constructor with vector clone
    2895         2050 :   TraitItemType (TraitItemType const &other)
    2896         4100 :     : TraitItem (other.locus), outer_attrs (other.outer_attrs),
    2897         2050 :       name (other.name)
    2898              :   {
    2899         2050 :     node_id = other.node_id;
    2900         2050 :     generic_params.reserve (other.generic_params.size ());
    2901         2086 :     for (const auto &e : other.generic_params)
    2902           36 :       generic_params.push_back (e->clone_generic_param ());
    2903         2050 :     type_param_bounds.reserve (other.type_param_bounds.size ());
    2904         2237 :     for (const auto &e : other.type_param_bounds)
    2905          187 :       type_param_bounds.push_back (e->clone_type_param_bound ());
    2906         2050 :   }
    2907              : 
    2908              :   // Overloaded assignment operator with vector clone
    2909              :   TraitItemType &operator= (TraitItemType const &other)
    2910              :   {
    2911              :     TraitItem::operator= (other);
    2912              :     outer_attrs = other.outer_attrs;
    2913              :     name = other.name;
    2914              :     locus = other.locus;
    2915              :     node_id = other.node_id;
    2916              : 
    2917              :     generic_params.reserve (other.generic_params.size ());
    2918              :     for (const auto &e : other.generic_params)
    2919              :       generic_params.push_back (e->clone_generic_param ());
    2920              :     type_param_bounds.reserve (other.type_param_bounds.size ());
    2921              :     for (const auto &e : other.type_param_bounds)
    2922              :       type_param_bounds.push_back (e->clone_type_param_bound ());
    2923              : 
    2924              :     return *this;
    2925              :   }
    2926              : 
    2927              :   // default move constructors
    2928              :   TraitItemType (TraitItemType &&other) = default;
    2929              :   TraitItemType &operator= (TraitItemType &&other) = default;
    2930              : 
    2931              :   std::string as_string () const override;
    2932              : 
    2933              :   void accept_vis (ASTVisitor &vis) override;
    2934              : 
    2935              :   // Invalid if name is empty, so base stripping on that.
    2936            0 :   void mark_for_strip () override { name = {""}; }
    2937         4449 :   bool is_marked_for_strip () const override { return name.empty (); }
    2938              : 
    2939              :   // TODO: this mutable getter seems really dodgy. Think up better way.
    2940        42569 :   std::vector<Attribute> &get_outer_attrs () { return outer_attrs; }
    2941          909 :   const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
    2942              : 
    2943              :   std::vector<std::unique_ptr<GenericParam>> &get_generic_params ()
    2944              :   {
    2945        33775 :     return generic_params;
    2946              :   }
    2947              :   const std::vector<std::unique_ptr<GenericParam>> &get_generic_params () const
    2948              :   {
    2949              :     return generic_params;
    2950              :   }
    2951              : 
    2952              :   std::vector<std::unique_ptr<TypeParamBound>> &get_type_param_bounds ()
    2953              :   {
    2954        33775 :     return type_param_bounds;
    2955              :   }
    2956              :   const std::vector<std::unique_ptr<TypeParamBound>> &
    2957              :   get_type_param_bounds () const
    2958              :   {
    2959              :     return type_param_bounds;
    2960              :   }
    2961              : 
    2962         6147 :   Identifier get_identifier () const { return name; }
    2963              : 
    2964              : protected:
    2965              :   // Clone function implementation as (not pure) virtual method
    2966         2050 :   TraitItemType *clone_associated_item_impl () const override
    2967              :   {
    2968         2050 :     return new TraitItemType (*this);
    2969              :   }
    2970              : };
    2971              : 
    2972              : // Rust trait item declaration AST node
    2973              : class Trait : public VisItem
    2974              : {
    2975              :   bool has_unsafe;
    2976              :   bool has_auto;
    2977              :   Identifier name;
    2978              :   std::vector<std::unique_ptr<GenericParam>> generic_params;
    2979              :   TypeParam self_param;
    2980              :   std::vector<std::unique_ptr<TypeParamBound>> type_param_bounds;
    2981              :   WhereClause where_clause;
    2982              :   std::vector<Attribute> inner_attrs;
    2983              :   std::vector<std::unique_ptr<AssociatedItem>> trait_items;
    2984              :   location_t locus;
    2985              : 
    2986              : public:
    2987              :   std::string as_string () const override;
    2988              : 
    2989              :   // Returns whether trait has generic parameters.
    2990         8513 :   bool has_generics () const { return !generic_params.empty (); }
    2991              : 
    2992              :   // Returns whether trait has type parameter bounds.
    2993         4523 :   bool has_type_param_bounds () const { return !type_param_bounds.empty (); }
    2994              : 
    2995              :   // Returns whether trait has where clause.
    2996       135279 :   bool has_where_clause () const { return !where_clause.is_empty (); }
    2997              : 
    2998              :   // Returns whether trait has trait items.
    2999           30 :   bool has_trait_items () const { return !trait_items.empty (); }
    3000              : 
    3001              :   // Returns whether trait has inner attributes.
    3002              :   bool has_inner_attrs () const { return !inner_attrs.empty (); }
    3003              : 
    3004       106486 :   Identifier get_identifier () const { return name; }
    3005              : 
    3006         4493 :   bool is_unsafe () const { return has_unsafe; }
    3007        13585 :   bool is_auto () const { return has_auto; }
    3008              : 
    3009              :   // Mega-constructor
    3010         4582 :   Trait (Identifier name, bool is_unsafe, bool is_auto,
    3011              :          std::vector<std::unique_ptr<GenericParam>> generic_params,
    3012              :          std::vector<std::unique_ptr<TypeParamBound>> type_param_bounds,
    3013              :          WhereClause where_clause,
    3014              :          std::vector<std::unique_ptr<AssociatedItem>> trait_items,
    3015              :          Visibility vis, std::vector<Attribute> outer_attrs,
    3016              :          std::vector<Attribute> inner_attrs, location_t locus)
    3017              :     : VisItem (std::move (vis), std::move (outer_attrs)),
    3018         9164 :       has_unsafe (is_unsafe), has_auto (is_auto), name (std::move (name)),
    3019         9164 :       generic_params (std::move (generic_params)), self_param ({"Self"}, locus),
    3020         4582 :       type_param_bounds (std::move (type_param_bounds)),
    3021         4582 :       where_clause (std::move (where_clause)),
    3022         4582 :       inner_attrs (std::move (inner_attrs)),
    3023         4582 :       trait_items (std::move (trait_items)), locus (locus)
    3024         4582 :   {}
    3025              : 
    3026              :   // Copy constructor with vector clone
    3027        10429 :   Trait (Trait const &other)
    3028        10429 :     : VisItem (other), has_unsafe (other.has_unsafe), has_auto (other.has_auto),
    3029        10429 :       name (other.name), self_param (other.self_param),
    3030        10429 :       where_clause (other.where_clause), inner_attrs (other.inner_attrs),
    3031        20858 :       locus (other.locus)
    3032              :   {
    3033        10429 :     generic_params.reserve (other.generic_params.size ());
    3034        12551 :     for (const auto &e : other.generic_params)
    3035         2122 :       generic_params.push_back (e->clone_generic_param ());
    3036              : 
    3037        10429 :     type_param_bounds.reserve (other.type_param_bounds.size ());
    3038        12552 :     for (const auto &e : other.type_param_bounds)
    3039         2123 :       type_param_bounds.push_back (e->clone_type_param_bound ());
    3040              : 
    3041        10429 :     trait_items.reserve (other.trait_items.size ());
    3042        21172 :     for (const auto &e : other.trait_items)
    3043        10743 :       trait_items.push_back (e->clone_associated_item ());
    3044        10429 :   }
    3045              : 
    3046              :   // Overloaded assignment operator with vector clone
    3047              :   Trait &operator= (Trait const &other)
    3048              :   {
    3049              :     VisItem::operator= (other);
    3050              :     name = other.name;
    3051              :     self_param = other.self_param;
    3052              :     has_unsafe = other.has_unsafe;
    3053              :     has_auto = other.has_auto;
    3054              :     where_clause = other.where_clause;
    3055              :     inner_attrs = other.inner_attrs;
    3056              :     locus = other.locus;
    3057              : 
    3058              :     generic_params.reserve (other.generic_params.size ());
    3059              :     for (const auto &e : other.generic_params)
    3060              :       generic_params.push_back (e->clone_generic_param ());
    3061              : 
    3062              :     type_param_bounds.reserve (other.type_param_bounds.size ());
    3063              :     for (const auto &e : other.type_param_bounds)
    3064              :       type_param_bounds.push_back (e->clone_type_param_bound ());
    3065              : 
    3066              :     trait_items.reserve (other.trait_items.size ());
    3067              :     for (const auto &e : other.trait_items)
    3068              :       trait_items.push_back (e->clone_associated_item ());
    3069              : 
    3070              :     return *this;
    3071              :   }
    3072              : 
    3073              :   // default move constructors
    3074              :   Trait (Trait &&other) = default;
    3075              :   Trait &operator= (Trait &&other) = default;
    3076              : 
    3077        31745 :   location_t get_locus () const override final { return locus; }
    3078              : 
    3079              :   void accept_vis (ASTVisitor &vis) override;
    3080              : 
    3081              :   // Invalid if trait name is empty, so base stripping on that.
    3082            2 :   void mark_for_strip () override { name = {""}; }
    3083        15040 :   bool is_marked_for_strip () const override { return name.empty (); }
    3084              : 
    3085              :   // TODO: think of better way to do this
    3086              :   const std::vector<Attribute> &get_inner_attrs () const { return inner_attrs; }
    3087       135310 :   std::vector<Attribute> &get_inner_attrs () { return inner_attrs; }
    3088              : 
    3089              :   const std::vector<std::unique_ptr<AssociatedItem>> &get_trait_items () const
    3090              :   {
    3091              :     return trait_items;
    3092              :   }
    3093        34077 :   std::vector<std::unique_ptr<AssociatedItem>> &get_trait_items ()
    3094              :   {
    3095       158822 :     return trait_items;
    3096              :   }
    3097              : 
    3098         1509 :   std::vector<std::unique_ptr<GenericParam>> &get_generic_params ()
    3099              :   {
    3100       136788 :     return generic_params;
    3101              :   }
    3102              :   const std::vector<std::unique_ptr<GenericParam>> &get_generic_params () const
    3103              :   {
    3104              :     return generic_params;
    3105              :   }
    3106              : 
    3107         3990 :   std::vector<std::unique_ptr<TypeParamBound>> &get_type_param_bounds ()
    3108              :   {
    3109       141234 :     return type_param_bounds;
    3110              :   }
    3111              :   const std::vector<std::unique_ptr<TypeParamBound>> &
    3112              :   get_type_param_bounds () const
    3113              :   {
    3114              :     return type_param_bounds;
    3115              :   }
    3116              : 
    3117          196 :   WhereClause &get_where_clause () { return where_clause; }
    3118              : 
    3119       120251 :   AST::TypeParam &get_implicit_self () { return self_param; }
    3120              : 
    3121        17967 :   Item::Kind get_item_kind () const override { return Item::Kind::Trait; }
    3122              : 
    3123              : protected:
    3124              :   /* Use covariance to implement clone function as returning this object
    3125              :    * rather than base */
    3126         5883 :   Trait *clone_item_impl () const override { return new Trait (*this); }
    3127              : };
    3128              : 
    3129              : // Implementation item declaration AST node - abstract base class
    3130              : class Impl : public VisItem
    3131              : {
    3132              :   // must be protected to allow subclasses to access them properly
    3133              : protected:
    3134              :   // bool has_generics;
    3135              :   // Generics generic_params;
    3136              :   std::vector<std::unique_ptr<GenericParam>> generic_params; // inlined
    3137              : 
    3138              :   std::unique_ptr<Type> trait_type;
    3139              : 
    3140              :   // bool has_where_clause;
    3141              :   WhereClause where_clause;
    3142              : 
    3143              :   // bool has_inner_attrs;
    3144              :   std::vector<Attribute> inner_attrs;
    3145              : 
    3146              : private:
    3147              :   // doesn't really need to be protected as write access probably not needed
    3148              :   location_t locus;
    3149              : 
    3150              : public:
    3151              :   // Returns whether impl has generic parameters.
    3152        14611 :   bool has_generics () const { return !generic_params.empty (); }
    3153              : 
    3154              :   // Returns whether impl has where clause.
    3155      1644736 :   bool has_where_clause () const { return !where_clause.is_empty (); }
    3156              : 
    3157              :   // Returns whether impl has inner attributes.
    3158              :   bool has_inner_attrs () const { return !inner_attrs.empty (); }
    3159              : 
    3160        20775 :   location_t get_locus () const override final { return locus; }
    3161              : 
    3162              :   // Invalid if trait type is null, so base stripping on that.
    3163           20 :   void mark_for_strip () override { trait_type = nullptr; }
    3164       252267 :   bool is_marked_for_strip () const override { return trait_type == nullptr; }
    3165              : 
    3166              :   // TODO: think of better way to do this
    3167              :   const std::vector<Attribute> &get_inner_attrs () const { return inner_attrs; }
    3168      1905873 :   std::vector<Attribute> &get_inner_attrs () { return inner_attrs; }
    3169              : 
    3170        10544 :   std::vector<std::unique_ptr<GenericParam>> &get_generic_params ()
    3171              :   {
    3172      1649221 :     return generic_params;
    3173              :   }
    3174              :   const std::vector<std::unique_ptr<GenericParam>> &get_generic_params () const
    3175              :   {
    3176              :     return generic_params;
    3177              :   }
    3178              : 
    3179              :   // TODO: is this better? Or is a "vis_block" better?
    3180        81638 :   WhereClause &get_where_clause () { return where_clause; }
    3181              : 
    3182              :   // TODO: is this better? Or is a "vis_block" better?
    3183      1677638 :   Type &get_type ()
    3184              :   {
    3185      1677638 :     rust_assert (trait_type != nullptr);
    3186      1677638 :     return *trait_type;
    3187              :   }
    3188              : 
    3189       520632 :   std::unique_ptr<Type> &get_type_ptr ()
    3190              :   {
    3191       520632 :     rust_assert (trait_type != nullptr);
    3192       520632 :     return trait_type;
    3193              :   }
    3194              : 
    3195        14464 :   Item::Kind get_item_kind () const override { return Item::Kind::Impl; }
    3196              : 
    3197              : protected:
    3198              :   // Mega-constructor
    3199        14762 :   Impl (std::vector<std::unique_ptr<GenericParam>> generic_params,
    3200              :         std::unique_ptr<Type> trait_type, WhereClause where_clause,
    3201              :         Visibility vis, std::vector<Attribute> inner_attrs,
    3202              :         std::vector<Attribute> outer_attrs, location_t locus)
    3203              :     : VisItem (std::move (vis), std::move (outer_attrs)),
    3204        14762 :       generic_params (std::move (generic_params)),
    3205        14762 :       trait_type (std::move (trait_type)),
    3206        14762 :       where_clause (std::move (where_clause)),
    3207        14762 :       inner_attrs (std::move (inner_attrs)), locus (locus)
    3208        14762 :   {}
    3209              : 
    3210              :   // Copy constructor
    3211        67836 :   Impl (Impl const &other)
    3212        67836 :     : VisItem (other), where_clause (other.where_clause),
    3213        67836 :       inner_attrs (other.inner_attrs), locus (other.locus)
    3214              :   {
    3215              :     // guard to prevent null dereference (only required if error state)
    3216        67836 :     if (other.trait_type != nullptr)
    3217        67836 :       trait_type = other.trait_type->clone_type ();
    3218              : 
    3219        67836 :     generic_params.reserve (other.generic_params.size ());
    3220       112624 :     for (const auto &e : other.generic_params)
    3221        44788 :       generic_params.push_back (e->clone_generic_param ());
    3222        67836 :   }
    3223              : 
    3224              :   // Assignment operator overload with cloning
    3225              :   Impl &operator= (Impl const &other)
    3226              :   {
    3227              :     VisItem::operator= (other);
    3228              :     where_clause = other.where_clause;
    3229              :     inner_attrs = other.inner_attrs;
    3230              :     locus = other.locus;
    3231              : 
    3232              :     // guard to prevent null dereference (only required if error state)
    3233              :     if (other.trait_type != nullptr)
    3234              :       trait_type = other.trait_type->clone_type ();
    3235              :     else
    3236              :       trait_type = nullptr;
    3237              : 
    3238              :     generic_params.reserve (other.generic_params.size ());
    3239              :     for (const auto &e : other.generic_params)
    3240              :       generic_params.push_back (e->clone_generic_param ());
    3241              : 
    3242              :     return *this;
    3243              :   }
    3244              : 
    3245              :   // move constructors
    3246              :   Impl (Impl &&other) = default;
    3247              :   Impl &operator= (Impl &&other) = default;
    3248              : };
    3249              : 
    3250              : // Regular "impl foo" impl block declaration AST node
    3251              : class InherentImpl : public Impl
    3252              : {
    3253              :   // bool has_impl_items;
    3254              :   std::vector<std::unique_ptr<AssociatedItem>> impl_items;
    3255              : 
    3256              : public:
    3257              :   std::string as_string () const override;
    3258              : 
    3259              :   // Returns whether inherent impl block has inherent impl items.
    3260            0 :   bool has_impl_items () const { return !impl_items.empty (); }
    3261              : 
    3262              :   // Mega-constructor
    3263         1557 :   InherentImpl (std::vector<std::unique_ptr<AssociatedItem>> impl_items,
    3264              :                 std::vector<std::unique_ptr<GenericParam>> generic_params,
    3265              :                 std::unique_ptr<Type> trait_type, WhereClause where_clause,
    3266              :                 Visibility vis, std::vector<Attribute> inner_attrs,
    3267              :                 std::vector<Attribute> outer_attrs, location_t locus)
    3268              :     : Impl (std::move (generic_params), std::move (trait_type),
    3269              :             std::move (where_clause), std::move (vis), std::move (inner_attrs),
    3270              :             std::move (outer_attrs), locus),
    3271         1557 :       impl_items (std::move (impl_items))
    3272         1557 :   {}
    3273              : 
    3274              :   // Copy constructor with vector clone
    3275         4800 :   InherentImpl (InherentImpl const &other) : Impl (other)
    3276              :   {
    3277         4800 :     impl_items.reserve (other.impl_items.size ());
    3278        26516 :     for (const auto &e : other.impl_items)
    3279        21716 :       impl_items.push_back (e->clone_associated_item ());
    3280         4800 :   }
    3281              : 
    3282              :   // Overloaded assignment operator with vector clone
    3283              :   InherentImpl &operator= (InherentImpl const &other)
    3284              :   {
    3285              :     Impl::operator= (other);
    3286              : 
    3287              :     impl_items.reserve (other.impl_items.size ());
    3288              :     for (const auto &e : other.impl_items)
    3289              :       impl_items.push_back (e->clone_associated_item ());
    3290              : 
    3291              :     return *this;
    3292              :   }
    3293              : 
    3294              :   // default move constructors
    3295              :   InherentImpl (InherentImpl &&other) = default;
    3296              :   InherentImpl &operator= (InherentImpl &&other) = default;
    3297              : 
    3298              :   void accept_vis (ASTVisitor &vis) override;
    3299              : 
    3300              :   // TODO: think of better way to do this
    3301              :   const std::vector<std::unique_ptr<AssociatedItem>> &get_impl_items () const
    3302              :   {
    3303              :     return impl_items;
    3304              :   }
    3305        27524 :   std::vector<std::unique_ptr<AssociatedItem>> &get_impl_items ()
    3306              :   {
    3307       109309 :     return impl_items;
    3308              :   }
    3309              : 
    3310              : protected:
    3311              :   /* Use covariance to implement clone function as returning this object
    3312              :    * rather than base */
    3313         3256 :   InherentImpl *clone_item_impl () const override
    3314              :   {
    3315         3256 :     return new InherentImpl (*this);
    3316              :   }
    3317              : };
    3318              : 
    3319              : // The "impl footrait for foo" impl block declaration AST node
    3320              : class TraitImpl : public Impl
    3321              : {
    3322              :   bool has_unsafe;
    3323              :   bool has_exclam;
    3324              :   TypePath trait_path;
    3325              : 
    3326              :   // bool has_impl_items;
    3327              :   std::vector<std::unique_ptr<AssociatedItem>> impl_items;
    3328              : 
    3329              : public:
    3330              :   std::string as_string () const override;
    3331              : 
    3332              :   // Returns whether trait impl has impl items.
    3333            0 :   bool has_impl_items () const { return !impl_items.empty (); }
    3334              : 
    3335              :   // Mega-constructor
    3336        13205 :   TraitImpl (TypePath trait_path, bool is_unsafe, bool has_exclam,
    3337              :              std::vector<std::unique_ptr<AssociatedItem>> impl_items,
    3338              :              std::vector<std::unique_ptr<GenericParam>> generic_params,
    3339              :              std::unique_ptr<Type> trait_type, WhereClause where_clause,
    3340              :              Visibility vis, std::vector<Attribute> inner_attrs,
    3341              :              std::vector<Attribute> outer_attrs, location_t locus)
    3342              :     : Impl (std::move (generic_params), std::move (trait_type),
    3343              :             std::move (where_clause), std::move (vis), std::move (inner_attrs),
    3344              :             std::move (outer_attrs), locus),
    3345        13205 :       has_unsafe (is_unsafe), has_exclam (has_exclam), trait_path (trait_path),
    3346        13205 :       impl_items (std::move (impl_items))
    3347        13205 :   {}
    3348              : 
    3349              :   // Copy constructor with vector clone
    3350        63036 :   TraitImpl (TraitImpl const &other)
    3351        63036 :     : Impl (other), has_unsafe (other.has_unsafe),
    3352        63036 :       has_exclam (other.has_exclam), trait_path (other.trait_path)
    3353              :   {
    3354        63036 :     impl_items.reserve (other.impl_items.size ());
    3355       146348 :     for (const auto &e : other.impl_items)
    3356        83312 :       impl_items.push_back (e->clone_associated_item ());
    3357        63036 :   }
    3358              : 
    3359              :   // Overloaded assignment operator with vector clone
    3360              :   TraitImpl &operator= (TraitImpl const &other)
    3361              :   {
    3362              :     Impl::operator= (other);
    3363              :     trait_path = other.trait_path;
    3364              :     has_unsafe = other.has_unsafe;
    3365              :     has_exclam = other.has_exclam;
    3366              : 
    3367              :     impl_items.reserve (other.impl_items.size ());
    3368              :     for (const auto &e : other.impl_items)
    3369              :       impl_items.push_back (e->clone_associated_item ());
    3370              : 
    3371              :     return *this;
    3372              :   }
    3373              : 
    3374              :   // move constructors
    3375              :   TraitImpl (TraitImpl &&other) = default;
    3376              :   TraitImpl &operator= (TraitImpl &&other) = default;
    3377              : 
    3378              :   void accept_vis (ASTVisitor &vis) override;
    3379              : 
    3380        13097 :   bool is_unsafe () const { return has_unsafe; };
    3381        31327 :   bool is_exclam () const { return has_exclam; }
    3382              : 
    3383              :   // TODO: think of better way to do this
    3384              :   const std::vector<std::unique_ptr<AssociatedItem>> &get_impl_items () const
    3385              :   {
    3386              :     return impl_items;
    3387              :   }
    3388       484918 :   std::vector<std::unique_ptr<AssociatedItem>> &get_impl_items ()
    3389              :   {
    3390      1802623 :     return impl_items;
    3391              :   }
    3392              : 
    3393              :   // TODO: is this better? Or is a "vis_block" better?
    3394      1815805 :   TypePath &get_trait_path () { return trait_path; }
    3395              : 
    3396              : protected:
    3397              :   /* Use covariance to implement clone function as returning this object
    3398              :    * rather than base */
    3399        49854 :   TraitImpl *clone_item_impl () const override { return new TraitImpl (*this); }
    3400              : };
    3401              : 
    3402              : #if 0
    3403              : // Abstract base class for an item used inside an extern block
    3404              : class ExternalItem
    3405              : {
    3406              :   // bool has_outer_attrs;
    3407              :   std::vector<Attribute> outer_attrs;
    3408              : 
    3409              :   // bool has_visibility;
    3410              :   Visibility visibility;
    3411              : 
    3412              :   Identifier item_name;
    3413              :   location_t locus;
    3414              : 
    3415              : public:
    3416              :   virtual ~ExternalItem () {}
    3417              : 
    3418              :   /* TODO: spec syntax rules state that "MacroInvocationSemi" can be used as
    3419              :    * ExternalItem, but text body isn't so clear. Adding MacroInvocationSemi
    3420              :    * support would require a lot of refactoring. */
    3421              : 
    3422              :   // Returns whether item has outer attributes.
    3423              :   bool has_outer_attrs () const { return !outer_attrs.empty (); }
    3424              : 
    3425              :   // Returns whether item has non-default visibility.
    3426              :   bool has_visibility () const { return !visibility.is_error (); }
    3427              : 
    3428              :   // Unique pointer custom clone function
    3429              :   std::unique_ptr<ExternalItem> clone_external_item () const
    3430              :   {
    3431              :     return std::unique_ptr<ExternalItem> (clone_external_item_impl ());
    3432              :   }
    3433              : 
    3434              :   virtual std::string as_string () const;
    3435              : 
    3436              :   location_t get_locus () const override final { return locus; }
    3437              : 
    3438              :   virtual void accept_vis (ASTVisitor &vis) = 0;
    3439              : 
    3440              :   // TODO: make virtual? Would be more flexible.
    3441              :   // Based on idea that name should never be empty.
    3442              :   void mark_for_strip () { item_name = ""; };
    3443              :   bool is_marked_for_strip () const { return item_name.empty (); };
    3444              : 
    3445              : protected:
    3446              :   ExternalItem (Identifier item_name, Visibility vis,
    3447              :                 std::vector<Attribute> outer_attrs, location_t locus)
    3448              :     : outer_attrs (std::move (outer_attrs)), visibility (std::move (vis)),
    3449              :       item_name (std::move (item_name)), locus (locus)
    3450              :   {}
    3451              : 
    3452              :   // Copy constructor
    3453              :   ExternalItem (ExternalItem const &other)
    3454              :     : outer_attrs (other.outer_attrs), visibility (other.visibility),
    3455              :       item_name (other.item_name), locus (other.locus)
    3456              :   {}
    3457              : 
    3458              :   // Overloaded assignment operator to clone
    3459              :   ExternalItem &operator= (ExternalItem const &other)
    3460              :   {
    3461              :     item_name = other.item_name;
    3462              :     visibility = other.visibility;
    3463              :     outer_attrs = other.outer_attrs;
    3464              :     locus = other.locus;
    3465              : 
    3466              :     return *this;
    3467              :   }
    3468              : 
    3469              :   // move constructors
    3470              :   ExternalItem (ExternalItem &&other) = default;
    3471              :   ExternalItem &operator= (ExternalItem &&other) = default;
    3472              : 
    3473              :   // Clone function implementation as pure virtual method
    3474              :   virtual ExternalItem *clone_external_item_impl () const = 0;
    3475              : 
    3476              :   // possibly make this public if required
    3477              :   std::string get_item_name () const { return item_name; }
    3478              : };
    3479              : #endif
    3480              : 
    3481              : // A foreign type defined outside the current crate.
    3482              : // https://rust-lang.github.io/rfcs/1861-extern-types.html
    3483              : class ExternalTypeItem : public ExternalItem
    3484              : {
    3485              :   std::vector<Attribute> outer_attrs;
    3486              : 
    3487              :   Visibility visibility;
    3488              :   Identifier item_name;
    3489              :   location_t locus;
    3490              : 
    3491              :   bool marked_for_strip;
    3492              : 
    3493              : public:
    3494            7 :   ExternalTypeItem (Identifier item_name, Visibility vis,
    3495              :                     std::vector<Attribute> outer_attrs, location_t locus)
    3496            7 :     : ExternalItem (), outer_attrs (std::move (outer_attrs)), visibility (vis),
    3497            7 :       item_name (std::move (item_name)), locus (locus), marked_for_strip (false)
    3498            7 :   {}
    3499              : 
    3500              :   // copy constructor
    3501           10 :   ExternalTypeItem (ExternalTypeItem const &other)
    3502           10 :     : ExternalItem (other.get_node_id ()), outer_attrs (other.outer_attrs),
    3503           10 :       visibility (other.visibility), item_name (other.item_name),
    3504           10 :       locus (other.locus), marked_for_strip (other.marked_for_strip)
    3505              :   {
    3506           10 :     node_id = other.node_id;
    3507           10 :   }
    3508              : 
    3509              :   ExternalTypeItem &operator= (ExternalTypeItem const &other)
    3510              :   {
    3511              :     node_id = other.node_id;
    3512              :     outer_attrs = other.outer_attrs;
    3513              :     visibility = other.visibility;
    3514              :     item_name = other.item_name;
    3515              :     locus = other.locus;
    3516              :     marked_for_strip = other.marked_for_strip;
    3517              : 
    3518              :     return *this;
    3519              :   }
    3520              : 
    3521              :   // move constructors
    3522              :   ExternalTypeItem (ExternalTypeItem &&other) = default;
    3523              :   ExternalTypeItem &operator= (ExternalTypeItem &&other) = default;
    3524              : 
    3525              :   std::string as_string () const override;
    3526              : 
    3527              :   void accept_vis (ASTVisitor &vis) override;
    3528              : 
    3529              :   // Returns whether item has outer attributes.
    3530              :   bool has_outer_attrs () const { return !outer_attrs.empty (); }
    3531              : 
    3532              :   // Returns whether item has non-default visibility.
    3533              :   bool has_visibility () const { return true; }
    3534              : 
    3535           57 :   location_t get_locus () const { return locus; }
    3536              : 
    3537            0 :   void mark_for_strip () override { marked_for_strip = true; };
    3538           47 :   bool is_marked_for_strip () const override { return marked_for_strip; };
    3539              : 
    3540              :   // TODO: this mutable getter seems really dodgy. Think up better way.
    3541          259 :   std::vector<Attribute> &get_outer_attrs () { return outer_attrs; }
    3542              :   const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
    3543              : 
    3544           54 :   Identifier get_identifier () const { return item_name; }
    3545              : 
    3546          222 :   Visibility &get_visibility () { return visibility; }
    3547              :   const Visibility &get_visibility () const { return visibility; }
    3548              : 
    3549              : protected:
    3550              :   /* Use covariance to implement clone function as returning this object
    3551              :    * rather than base */
    3552           10 :   ExternalTypeItem *clone_external_item_impl () const override
    3553              :   {
    3554           10 :     return new ExternalTypeItem (*this);
    3555              :   }
    3556              : };
    3557              : 
    3558              : // A static item used in an extern block
    3559              : class ExternalStaticItem : public ExternalItem
    3560              : {
    3561              :   // bool has_outer_attrs;
    3562              :   std::vector<Attribute> outer_attrs;
    3563              : 
    3564              :   // bool has_visibility;
    3565              :   Visibility visibility;
    3566              : 
    3567              :   Identifier item_name;
    3568              :   location_t locus;
    3569              : 
    3570              :   bool has_mut;
    3571              :   std::unique_ptr<Type> item_type;
    3572              : 
    3573              : public:
    3574            1 :   ExternalStaticItem (Identifier item_name, std::unique_ptr<Type> item_type,
    3575              :                       bool is_mut, Visibility vis,
    3576              :                       std::vector<Attribute> outer_attrs, location_t locus)
    3577            1 :     : ExternalItem (), outer_attrs (std::move (outer_attrs)),
    3578            1 :       visibility (std::move (vis)), item_name (std::move (item_name)),
    3579            1 :       locus (locus), has_mut (is_mut), item_type (std::move (item_type))
    3580            1 :   {}
    3581              : 
    3582              :   // Copy constructor
    3583            2 :   ExternalStaticItem (ExternalStaticItem const &other)
    3584            2 :     : ExternalItem (other.get_node_id ()), outer_attrs (other.outer_attrs),
    3585            2 :       visibility (other.visibility), item_name (other.item_name),
    3586            4 :       locus (other.locus), has_mut (other.has_mut)
    3587              :   {
    3588            2 :     node_id = other.node_id;
    3589              :     // guard to prevent null dereference (only required if error state)
    3590            2 :     if (other.item_type != nullptr)
    3591            2 :       item_type = other.item_type->clone_type ();
    3592            2 :   }
    3593              : 
    3594              :   // Overloaded assignment operator to clone
    3595              :   ExternalStaticItem &operator= (ExternalStaticItem const &other)
    3596              :   {
    3597              :     node_id = other.node_id;
    3598              :     outer_attrs = other.outer_attrs;
    3599              :     visibility = other.visibility;
    3600              :     item_name = other.item_name;
    3601              :     locus = other.locus;
    3602              :     has_mut = other.has_mut;
    3603              : 
    3604              :     // guard to prevent null dereference (only required if error state)
    3605              :     if (other.item_type != nullptr)
    3606              :       item_type = other.item_type->clone_type ();
    3607              :     else
    3608              :       item_type = nullptr;
    3609              : 
    3610              :     return *this;
    3611              :   }
    3612              : 
    3613              :   // move constructors
    3614              :   ExternalStaticItem (ExternalStaticItem &&other) = default;
    3615              :   ExternalStaticItem &operator= (ExternalStaticItem &&other) = default;
    3616              : 
    3617              :   std::string as_string () const override;
    3618              : 
    3619              :   void accept_vis (ASTVisitor &vis) override;
    3620              : 
    3621              :   // Returns whether item has outer attributes.
    3622              :   bool has_outer_attrs () const { return !outer_attrs.empty (); }
    3623              : 
    3624              :   // Returns whether item has non-default visibility.
    3625              :   bool has_visibility () const { return true; }
    3626              : 
    3627            4 :   location_t get_locus () const { return locus; }
    3628              : 
    3629              :   // Based on idea that type should never be null.
    3630            0 :   void mark_for_strip () override { item_type = nullptr; };
    3631            3 :   bool is_marked_for_strip () const override { return item_type == nullptr; };
    3632              : 
    3633              :   // TODO: this mutable getter seems really dodgy. Think up better way.
    3634           24 :   std::vector<Attribute> &get_outer_attrs () { return outer_attrs; }
    3635              :   const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
    3636              : 
    3637              :   // TODO: is this better? Or is a "vis_block" better?
    3638           19 :   Type &get_type ()
    3639              :   {
    3640           19 :     rust_assert (item_type != nullptr);
    3641           19 :     return *item_type;
    3642              :   }
    3643              : 
    3644            5 :   std::unique_ptr<Type> &get_type_ptr ()
    3645              :   {
    3646            5 :     rust_assert (item_type != nullptr);
    3647            5 :     return item_type;
    3648              :   }
    3649              : 
    3650            4 :   Identifier get_identifier () const { return item_name; }
    3651              : 
    3652           22 :   Visibility &get_visibility () { return visibility; }
    3653              : 
    3654              :   const Visibility &get_visibility () const { return visibility; }
    3655              : 
    3656            1 :   bool is_mut () const { return has_mut; }
    3657              : 
    3658              : protected:
    3659              :   /* Use covariance to implement clone function as returning this object
    3660              :    * rather than base */
    3661            2 :   ExternalStaticItem *clone_external_item_impl () const override
    3662              :   {
    3663            2 :     return new ExternalStaticItem (*this);
    3664              :   }
    3665              : };
    3666              : 
    3667              : // An extern block AST node
    3668              : class ExternBlock : public VisItem
    3669              : {
    3670              :   // bool has_abi;
    3671              :   std::string abi;
    3672              : 
    3673              :   // bool has_inner_attrs;
    3674              :   std::vector<Attribute> inner_attrs;
    3675              : 
    3676              :   // bool has_extern_items;
    3677              :   std::vector<std::unique_ptr<ExternalItem>> extern_items;
    3678              : 
    3679              :   location_t locus;
    3680              : 
    3681              :   // TODO: find another way to store this to save memory?
    3682              :   bool marked_for_strip = false;
    3683              : 
    3684              : public:
    3685              :   std::string as_string () const override;
    3686              : 
    3687              :   // Returns whether extern block has inner attributes.
    3688              :   bool has_inner_attrs () const { return !inner_attrs.empty (); }
    3689              : 
    3690              :   // Returns whether extern block has extern items.
    3691            0 :   bool has_extern_items () const { return !extern_items.empty (); }
    3692              : 
    3693              :   // Returns whether extern block has ABI name.
    3694         7000 :   bool has_abi () const { return !abi.empty (); }
    3695              : 
    3696        10454 :   std::string get_abi () const { return abi; }
    3697              : 
    3698         1786 :   ExternBlock (std::string abi,
    3699              :                std::vector<std::unique_ptr<ExternalItem>> extern_items,
    3700              :                Visibility vis, std::vector<Attribute> inner_attrs,
    3701              :                std::vector<Attribute> outer_attrs, location_t locus)
    3702         1786 :     : VisItem (std::move (vis), std::move (outer_attrs)), abi (std::move (abi)),
    3703         1786 :       inner_attrs (std::move (inner_attrs)),
    3704         1786 :       extern_items (std::move (extern_items)), locus (locus)
    3705         1786 :   {}
    3706              : 
    3707              :   // Copy constructor with vector clone
    3708         3973 :   ExternBlock (ExternBlock const &other)
    3709         3973 :     : VisItem (other), abi (other.abi), inner_attrs (other.inner_attrs),
    3710         7946 :       locus (other.locus), marked_for_strip (other.marked_for_strip)
    3711              :   {
    3712         3973 :     extern_items.reserve (other.extern_items.size ());
    3713        12983 :     for (const auto &e : other.extern_items)
    3714         9010 :       extern_items.push_back (e->clone_external_item ());
    3715         3973 :   }
    3716              : 
    3717              :   // Overloaded assignment operator with vector clone
    3718              :   ExternBlock &operator= (ExternBlock const &other)
    3719              :   {
    3720              :     VisItem::operator= (other);
    3721              :     abi = other.abi;
    3722              :     inner_attrs = other.inner_attrs;
    3723              :     locus = other.locus;
    3724              :     marked_for_strip = other.marked_for_strip;
    3725              : 
    3726              :     extern_items.reserve (other.extern_items.size ());
    3727              :     for (const auto &e : other.extern_items)
    3728              :       extern_items.push_back (e->clone_external_item ());
    3729              : 
    3730              :     return *this;
    3731              :   }
    3732              : 
    3733              :   // move constructors
    3734              :   ExternBlock (ExternBlock &&other) = default;
    3735              :   ExternBlock &operator= (ExternBlock &&other) = default;
    3736              : 
    3737         4767 :   location_t get_locus () const override final { return locus; }
    3738              : 
    3739              :   void accept_vis (ASTVisitor &vis) override;
    3740              : 
    3741              :   // Can't think of any invalid invariants, so store boolean.
    3742            0 :   void mark_for_strip () override { marked_for_strip = true; }
    3743         5427 :   bool is_marked_for_strip () const override { return marked_for_strip; }
    3744              : 
    3745              :   // TODO: think of better way to do this
    3746              :   const std::vector<std::unique_ptr<ExternalItem>> &get_extern_items () const
    3747              :   {
    3748              :     return extern_items;
    3749              :   }
    3750        12703 :   std::vector<std::unique_ptr<ExternalItem>> &get_extern_items ()
    3751              :   {
    3752        52115 :     return extern_items;
    3753              :   }
    3754              : 
    3755              :   // TODO: think of better way to do this
    3756              :   const std::vector<Attribute> &get_inner_attrs () const { return inner_attrs; }
    3757        50439 :   std::vector<Attribute> &get_inner_attrs () { return inner_attrs; }
    3758              : 
    3759           68 :   Item::Kind get_item_kind () const override { return Item::Kind::ExternBlock; }
    3760              : 
    3761              : protected:
    3762              :   /* Use covariance to implement clone function as returning this object
    3763              :    * rather than base */
    3764         2189 :   ExternBlock *clone_item_impl () const override
    3765              :   {
    3766         2189 :     return new ExternBlock (*this);
    3767              :   }
    3768              : };
    3769              : 
    3770              : class MacroRulesDefinition;
    3771              : } // namespace AST
    3772              : } // namespace Rust
    3773              : 
    3774              : #endif
        

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