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