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

Generated by: LCOV version 2.4-beta

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