1 // Copyright (C) 2021-2023 Free Software Foundation, Inc.
3 // This file is part of GCC.
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
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
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/>.
19 // The idea is that all reachable symbols are live, codes called
20 // from live codes are live, and everything else is dead.
22 #include "rust-lint-marklive.h"
23 #include "rust-hir-full.h"
24 #include "rust-name-resolver.h"
29 // This class trys to find the live symbols which can be used as
32 // 1. TODO: explicit live
33 // - Attribute like #[allow(dead_code)]
34 // - Attribute like #[lang=".."], it's not a intra-crate item.
35 // 2. TODO: foreign item
36 class FindEntryPoint
: public MarkLiveBase
38 using Rust::Analysis::MarkLiveBase::visit
;
41 static std::vector
<HirId
> find (HIR::Crate
&crate
)
43 FindEntryPoint findEntryPoint
;
44 for (auto it
= crate
.items
.begin (); it
!= crate
.items
.end (); it
++)
46 it
->get ()->accept_vis (findEntryPoint
);
48 return findEntryPoint
.getEntryPoint ();
51 // TODO not only fn main can be a entry point.
52 void visit (HIR::Function
&function
) override
54 if (function
.get_function_name () == "main")
56 entryPoints
.push_back (function
.get_mappings ().get_hirid ());
61 FindEntryPoint () : MarkLiveBase () {}
62 std::vector
<HirId
> entryPoints
;
63 std::vector
<HirId
> getEntryPoint () { return entryPoints
; }
67 MarkLive::Analysis (HIR::Crate
&crate
)
69 MarkLive
marklive (FindEntryPoint::find (crate
));
72 return marklive
.liveSymbols
;
75 // pop a live symbol from worklist every iteration,
76 // if it's a function then walk the function body, and
77 // 1. save all the live symbols in worklist which is
79 // 2. save all the live symbols in liveSymbols
81 MarkLive::go (HIR::Crate
&crate
)
83 while (!worklist
.empty ())
85 HirId hirId
= worklist
.back ();
87 scannedSymbols
.emplace (hirId
);
88 HIR::Item
*item
= mappings
->lookup_hir_item (hirId
);
89 liveSymbols
.emplace (hirId
);
92 item
->accept_vis (*this);
95 { // the item maybe inside a trait impl
96 HirId parent_impl_id
= UNKNOWN_HIRID
;
97 HIR::ImplItem
*implItem
98 = mappings
->lookup_hir_implitem (hirId
, &parent_impl_id
);
99 if (implItem
!= nullptr)
100 implItem
->accept_vis (*this);
106 MarkLive::visit (HIR::PathInExpression
&expr
)
108 // We should iterate every path segment in order to mark the struct which
109 // is used in expression like Foo::bar(), we should mark the Foo alive.
110 expr
.iterate_path_segments ([&] (HIR::PathExprSegment
&seg
) -> bool {
111 return visit_path_segment (seg
);
114 // after iterate the path segments, we should mark functions and associated
116 NodeId ast_node_id
= expr
.get_mappings ().get_nodeid ();
117 NodeId ref_node_id
= UNKNOWN_NODEID
;
118 find_ref_node_id (ast_node_id
, ref_node_id
);
122 bool ok
= mappings
->lookup_node_to_hir (ref_node_id
, &ref
);
125 // it must resolve to some kind of HIR::Item or HIR::InheritImplItem
126 HIR::Item
*resolved_item
= mappings
->lookup_hir_item (ref
);
127 if (resolved_item
!= nullptr)
129 mark_hir_id (resolved_item
->get_mappings ().get_hirid ());
133 HirId parent_impl_id
= UNKNOWN_HIRID
;
134 HIR::ImplItem
*resolved_item
135 = mappings
->lookup_hir_implitem (ref
, &parent_impl_id
);
136 if (resolved_item
!= nullptr)
138 mark_hir_id (resolved_item
->get_impl_mappings ().get_hirid ());
144 MarkLive::visit (HIR::MethodCallExpr
&expr
)
146 expr
.get_receiver ()->accept_vis (*this);
147 visit_path_segment (expr
.get_method_name ());
148 for (auto &argument
: expr
.get_arguments ())
149 argument
->accept_vis (*this);
151 // Trying to find the method definition and mark it alive.
152 NodeId ast_node_id
= expr
.get_mappings ().get_nodeid ();
153 NodeId ref_node_id
= UNKNOWN_NODEID
;
154 find_ref_node_id (ast_node_id
, ref_node_id
);
158 bool ok
= mappings
->lookup_node_to_hir (ref_node_id
, &ref
);
164 MarkLive::visit_path_segment (HIR::PathExprSegment seg
)
166 NodeId ast_node_id
= seg
.get_mappings ().get_nodeid ();
167 NodeId ref_node_id
= UNKNOWN_NODEID
;
169 // There are two different kinds of segment for us.
170 // 1. function segment
171 // like the symbol "foo" in expression `foo()`.
173 // like the symbol "Foo" in expression `Foo{a: 1, b: 2}`
175 // We should mark them alive all and ignoring other kind of segments.
176 // If the segment we dont care then just return false is fine
177 if (!resolver
->lookup_resolved_name (ast_node_id
, &ref_node_id
))
179 if (!resolver
->lookup_resolved_type (ast_node_id
, &ref_node_id
))
183 bool ok
= mappings
->lookup_node_to_hir (ref_node_id
, &ref
);
190 MarkLive::visit (HIR::FieldAccessExpr
&expr
)
192 // visit receiver at first
193 expr
.get_receiver_expr ()->accept_vis (*this);
195 // resolve the receiver back to ADT type
196 TyTy::BaseType
*receiver
= nullptr;
197 if (!tyctx
->lookup_type (
198 expr
.get_receiver_expr ()->get_mappings ().get_hirid (), &receiver
))
200 rust_error_at (expr
.get_receiver_expr ()->get_locus (),
201 "unresolved type for receiver");
204 TyTy::ADTType
*adt
= nullptr;
205 if (receiver
->get_kind () == TyTy::TypeKind::ADT
)
207 adt
= static_cast<TyTy::ADTType
*> (receiver
);
209 else if (receiver
->get_kind () == TyTy::TypeKind::REF
)
211 TyTy::ReferenceType
*r
= static_cast<TyTy::ReferenceType
*> (receiver
);
212 TyTy::BaseType
*b
= r
->get_base ();
213 rust_assert (b
->get_kind () == TyTy::TypeKind::ADT
);
215 adt
= static_cast<TyTy::ADTType
*> (b
);
218 rust_assert (adt
!= nullptr);
219 rust_assert (!adt
->is_enum ());
220 rust_assert (adt
->number_of_variants () == 1);
222 TyTy::VariantDef
*variant
= adt
->get_variants ().at (0);
224 // get the field index
226 TyTy::StructFieldType
*field
;
227 bool ok
= variant
->lookup_field (expr
.get_field_name (), &field
, &index
);
229 if (index
>= variant
->num_fields ())
231 rust_error_at (expr
.get_receiver_expr ()->get_locus (),
232 "cannot access struct %s by index: %lu",
233 adt
->get_name ().c_str (), (unsigned long) index
);
237 // get the field hir id
238 HirId field_id
= field
->get_ref ();
239 mark_hir_id (field_id
);
243 MarkLive::visit (HIR::TupleIndexExpr
&expr
)
245 // TODO: unused tuple field detection
246 expr
.get_tuple_expr ()->accept_vis (*this);
250 MarkLive::visit (HIR::TypeAlias
&alias
)
253 resolver
->lookup_resolved_type (
254 alias
.get_type_aliased ()->get_mappings ().get_nodeid (), &ast_node_id
);
256 bool ok
= mappings
->lookup_node_to_hir (ast_node_id
, &hir_id
);
258 mark_hir_id (hir_id
);
262 MarkLive::mark_hir_id (HirId id
)
264 if (scannedSymbols
.find (id
) == scannedSymbols
.end ())
266 worklist
.push_back (id
);
268 liveSymbols
.emplace (id
);
272 MarkLive::find_ref_node_id (NodeId ast_node_id
, NodeId
&ref_node_id
)
274 if (!resolver
->lookup_resolved_name (ast_node_id
, &ref_node_id
))
276 bool ok
= resolver
->lookup_resolved_type (ast_node_id
, &ref_node_id
);
281 } // namespace Analysis