(root)/
gcc-13.2.0/
gcc/
rust/
checks/
lints/
rust-lint-scan-deadcode.h
       1  // Copyright (C) 2021-2023 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_HIR_SCAN_DEADCODE
      20  #define RUST_HIR_SCAN_DEADCODE
      21  
      22  #include "rust-hir-full-decls.h"
      23  #include "rust-hir-map.h"
      24  #include "rust-lint-marklive.h"
      25  #include "rust-name-resolver.h"
      26  #include "rust-diagnostics.h"
      27  
      28  namespace Rust {
      29  namespace Analysis {
      30  
      31  // Scan item symbols and warn the symbol if it is not in the live_symbols set.
      32  // There are three kinds of item we should handle in this pass.
      33  // 1. Function item
      34  // 2. The function item in the impl block without trait
      35  // 3. StructStruct, e.g., `Struct Foo{one: 1, two: 2}`. Furthermore, the unused
      36  //    struct fields will be warned too.
      37  // 4. TupleStruct, e.g., `Struct Foo(i32, i32)`
      38  class ScanDeadcode : public MarkLiveBase
      39  {
      40    using Rust::Analysis::MarkLiveBase::visit;
      41  
      42  public:
      43    static void Scan (HIR::Crate &crate)
      44    {
      45      std::set<HirId> live_symbols = Analysis::MarkLive::Analysis (crate);
      46      ScanDeadcode sdc (live_symbols);
      47      for (auto it = crate.items.begin (); it != crate.items.end (); it++)
      48        {
      49  	it->get ()->accept_vis (sdc);
      50        }
      51    };
      52  
      53    void visit (HIR::Function &function) override
      54    {
      55      HirId hirId = function.get_mappings ().get_hirid ();
      56      if (should_warn (hirId) && !function.get_visibility ().is_public ())
      57        {
      58  	if (mappings->is_impl_item (hirId))
      59  	  {
      60  	    HIR::ImplBlock *implBlock
      61  	      = mappings->lookup_associated_impl (hirId);
      62  	    if (!implBlock->has_trait_ref ())
      63  	      {
      64  		rust_warning_at (function.get_locus (), 0,
      65  				 "associated function is never used: %<%s%>",
      66  				 function.get_function_name ().c_str ());
      67  	      }
      68  	  }
      69  	else
      70  	  {
      71  	    rust_warning_at (function.get_locus (), 0,
      72  			     "function is never used: %<%s%>",
      73  			     function.get_function_name ().c_str ());
      74  	  }
      75        }
      76    }
      77  
      78    void visit (HIR::StructStruct &stct) override
      79    {
      80      HirId hirId = stct.get_mappings ().get_hirid ();
      81      if (should_warn (hirId) && !stct.get_visibility ().is_public ())
      82        {
      83  	bool name_starts_underscore = stct.get_identifier ().at (0) == '_';
      84  	if (!name_starts_underscore)
      85  	  rust_warning_at (stct.get_locus (), 0,
      86  			   "struct is never constructed: %<%s%>",
      87  			   stct.get_identifier ().c_str ());
      88        }
      89      else
      90        {
      91  	// only warn the unused fields when in unwarned struct.
      92  	for (auto &field : stct.get_fields ())
      93  	  {
      94  	    HirId field_hir_id = field.get_mappings ().get_hirid ();
      95  	    if (should_warn (field_hir_id)
      96  		&& !field.get_visibility ().is_public ())
      97  	      {
      98  		rust_warning_at (field.get_locus (), 0,
      99  				 "field is never read: %<%s%>",
     100  				 field.get_field_name ().c_str ());
     101  	      }
     102  	  }
     103        }
     104    }
     105  
     106    void visit (HIR::TupleStruct &stct) override
     107    {
     108      // only warn tuple struct unconstructed, and ignoring unused field
     109      HirId hirId = stct.get_mappings ().get_hirid ();
     110      if (should_warn (hirId) && !stct.get_visibility ().is_public ())
     111        {
     112  	rust_warning_at (stct.get_locus (), 0,
     113  			 "struct is never constructed: %<%s%>",
     114  			 stct.get_identifier ().c_str ());
     115        }
     116    }
     117  
     118    void visit (HIR::ImplBlock &blc) override
     119    {
     120      if (blc.has_impl_items ())
     121        {
     122  	for (auto &implItem : blc.get_impl_items ())
     123  	  {
     124  	    implItem->accept_vis (*this);
     125  	  }
     126        }
     127    }
     128  
     129    void visit (HIR::Module &mod) override
     130    {
     131      for (auto &item : mod.get_items ())
     132        item->accept_vis (*this);
     133    }
     134  
     135  private:
     136    std::set<HirId> live_symbols;
     137    Resolver::Resolver *resolver;
     138    Analysis::Mappings *mappings;
     139  
     140    ScanDeadcode (std::set<HirId> &live_symbols)
     141      : live_symbols (live_symbols), resolver (Resolver::Resolver::get ()),
     142        mappings (Analysis::Mappings::get ()){};
     143  
     144    bool should_warn (HirId hirId)
     145    {
     146      // TODO: There are more condition to check if should warn, i.e visibility,
     147      // attributes.
     148      return live_symbols.find (hirId) == live_symbols.end ();
     149    }
     150  };
     151  
     152  } // namespace Analysis
     153  } // namespace Rust
     154  
     155  #endif