1 // Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 use hir
::map
::definitions
::*;
12 use hir
::def_id
::{CRATE_DEF_INDEX, DefIndex, DefIndexAddressSpace}
;
15 use syntax
::ext
::hygiene
::Mark
;
17 use syntax
::symbol
::keywords
;
18 use syntax
::symbol
::Symbol
;
20 use hir
::map
::{ITEM_LIKE_SPACE, REGULAR_SPACE}
;
22 /// Creates def ids for nodes in the AST.
23 pub struct DefCollector
<'a
> {
24 definitions
: &'a
mut Definitions
,
25 parent_def
: Option
<DefIndex
>,
27 pub visit_macro_invoc
: Option
<&'a
mut FnMut(MacroInvocationData
)>,
30 pub struct MacroInvocationData
{
32 pub def_index
: DefIndex
,
36 impl<'a
> DefCollector
<'a
> {
37 pub fn new(definitions
: &'a
mut Definitions
, expansion
: Mark
) -> Self {
42 visit_macro_invoc
: None
,
46 pub fn collect_root(&mut self, crate_name
: &str, crate_disambiguator
: &str) {
47 let root
= self.definitions
.create_root_def(crate_name
,
49 assert_eq
!(root
, CRATE_DEF_INDEX
);
50 self.parent_def
= Some(root
);
53 fn create_def(&mut self,
56 address_space
: DefIndexAddressSpace
)
58 let parent_def
= self.parent_def
.unwrap();
59 debug
!("create_def(node_id={:?}, data={:?}, parent_def={:?})", node_id
, data
, parent_def
);
61 .create_def_with_parent(parent_def
, node_id
, data
, address_space
, self.expansion
)
64 pub fn with_parent
<F
: FnOnce(&mut Self)>(&mut self, parent_def
: DefIndex
, f
: F
) {
65 let parent
= self.parent_def
;
66 self.parent_def
= Some(parent_def
);
68 self.parent_def
= parent
;
71 pub fn visit_const_expr(&mut self, expr
: &Expr
) {
73 // Find the node which will be used after lowering.
74 ExprKind
::Paren(ref inner
) => return self.visit_const_expr(inner
),
75 ExprKind
::Mac(..) => return self.visit_macro_invoc(expr
.id
, true),
76 // FIXME(eddyb) Closures should have separate
77 // function definition IDs and expression IDs.
78 ExprKind
::Closure(..) => return,
82 self.create_def(expr
.id
, DefPathData
::Initializer
, REGULAR_SPACE
);
85 fn visit_macro_invoc(&mut self, id
: NodeId
, const_expr
: bool
) {
86 if let Some(ref mut visit
) = self.visit_macro_invoc
{
87 visit(MacroInvocationData
{
88 mark
: id
.placeholder_to_mark(),
90 def_index
: self.parent_def
.unwrap(),
96 impl<'a
> visit
::Visitor
<'a
> for DefCollector
<'a
> {
97 fn visit_item(&mut self, i
: &'a Item
) {
98 debug
!("visit_item: {:?}", i
);
100 // Pick the def data. This need not be unique, but the more
101 // information we encapsulate into
102 let def_data
= match i
.node
{
103 ItemKind
::DefaultImpl(..) | ItemKind
::Impl(..) =>
105 ItemKind
::Enum(..) | ItemKind
::Struct(..) | ItemKind
::Union(..) | ItemKind
::Trait(..) |
106 ItemKind
::ExternCrate(..) | ItemKind
::ForeignMod(..) | ItemKind
::Ty(..) =>
107 DefPathData
::TypeNs(i
.ident
.name
.as_str()),
108 ItemKind
::Mod(..) if i
.ident
== keywords
::Invalid
.ident() => {
109 return visit
::walk_item(self, i
);
111 ItemKind
::Mod(..) => DefPathData
::Module(i
.ident
.name
.as_str()),
112 ItemKind
::Static(..) | ItemKind
::Const(..) | ItemKind
::Fn(..) =>
113 DefPathData
::ValueNs(i
.ident
.name
.as_str()),
114 ItemKind
::MacroDef(..) => DefPathData
::MacroDef(i
.ident
.name
.as_str()),
115 ItemKind
::Mac(..) => return self.visit_macro_invoc(i
.id
, false),
116 ItemKind
::GlobalAsm(..) => DefPathData
::Misc
,
117 ItemKind
::Use(ref view_path
) => {
118 match view_path
.node
{
119 ViewPathGlob(..) => {}
121 // FIXME(eddyb) Should use the real name. Which namespace?
122 ViewPathSimple(..) => {}
123 ViewPathList(_
, ref imports
) => {
124 for import
in imports
{
125 self.create_def(import
.node
.id
,
134 let def
= self.create_def(i
.id
, def_data
, ITEM_LIKE_SPACE
);
136 self.with_parent(def
, |this
| {
138 ItemKind
::Enum(ref enum_definition
, _
) => {
139 for v
in &enum_definition
.variants
{
140 let variant_def_index
=
141 this
.create_def(v
.node
.data
.id(),
142 DefPathData
::EnumVariant(v
.node
.name
.name
.as_str()),
144 this
.with_parent(variant_def_index
, |this
| {
145 for (index
, field
) in v
.node
.data
.fields().iter().enumerate() {
146 let name
= field
.ident
.map(|ident
| ident
.name
)
147 .unwrap_or_else(|| Symbol
::intern(&index
.to_string()));
148 this
.create_def(field
.id
,
149 DefPathData
::Field(name
.as_str()),
153 if let Some(ref expr
) = v
.node
.disr_expr
{
154 this
.visit_const_expr(expr
);
159 ItemKind
::Struct(ref struct_def
, _
) | ItemKind
::Union(ref struct_def
, _
) => {
160 // If this is a tuple-like struct, register the constructor.
161 if !struct_def
.is_struct() {
162 this
.create_def(struct_def
.id(),
163 DefPathData
::StructCtor
,
167 for (index
, field
) in struct_def
.fields().iter().enumerate() {
168 let name
= field
.ident
.map(|ident
| ident
.name
)
169 .unwrap_or_else(|| Symbol
::intern(&index
.to_string()));
170 this
.create_def(field
.id
, DefPathData
::Field(name
.as_str()), REGULAR_SPACE
);
175 visit
::walk_item(this
, i
);
179 fn visit_foreign_item(&mut self, foreign_item
: &'a ForeignItem
) {
180 let def
= self.create_def(foreign_item
.id
,
181 DefPathData
::ValueNs(foreign_item
.ident
.name
.as_str()),
184 self.with_parent(def
, |this
| {
185 visit
::walk_foreign_item(this
, foreign_item
);
189 fn visit_generics(&mut self, generics
: &'a Generics
) {
190 for ty_param
in generics
.ty_params
.iter() {
191 self.create_def(ty_param
.id
,
192 DefPathData
::TypeParam(ty_param
.ident
.name
.as_str()),
196 visit
::walk_generics(self, generics
);
199 fn visit_trait_item(&mut self, ti
: &'a TraitItem
) {
200 let def_data
= match ti
.node
{
201 TraitItemKind
::Method(..) | TraitItemKind
::Const(..) =>
202 DefPathData
::ValueNs(ti
.ident
.name
.as_str()),
203 TraitItemKind
::Type(..) => DefPathData
::TypeNs(ti
.ident
.name
.as_str()),
204 TraitItemKind
::Macro(..) => return self.visit_macro_invoc(ti
.id
, false),
207 let def
= self.create_def(ti
.id
, def_data
, ITEM_LIKE_SPACE
);
208 self.with_parent(def
, |this
| {
209 if let TraitItemKind
::Const(_
, Some(ref expr
)) = ti
.node
{
210 this
.visit_const_expr(expr
);
213 visit
::walk_trait_item(this
, ti
);
217 fn visit_impl_item(&mut self, ii
: &'a ImplItem
) {
218 let def_data
= match ii
.node
{
219 ImplItemKind
::Method(..) | ImplItemKind
::Const(..) =>
220 DefPathData
::ValueNs(ii
.ident
.name
.as_str()),
221 ImplItemKind
::Type(..) => DefPathData
::TypeNs(ii
.ident
.name
.as_str()),
222 ImplItemKind
::Macro(..) => return self.visit_macro_invoc(ii
.id
, false),
225 let def
= self.create_def(ii
.id
, def_data
, ITEM_LIKE_SPACE
);
226 self.with_parent(def
, |this
| {
227 if let ImplItemKind
::Const(_
, ref expr
) = ii
.node
{
228 this
.visit_const_expr(expr
);
231 visit
::walk_impl_item(this
, ii
);
235 fn visit_pat(&mut self, pat
: &'a Pat
) {
237 PatKind
::Mac(..) => return self.visit_macro_invoc(pat
.id
, false),
238 _
=> visit
::walk_pat(self, pat
),
242 fn visit_expr(&mut self, expr
: &'a Expr
) {
243 let parent_def
= self.parent_def
;
246 ExprKind
::Mac(..) => return self.visit_macro_invoc(expr
.id
, false),
247 ExprKind
::Repeat(_
, ref count
) => self.visit_const_expr(count
),
248 ExprKind
::Closure(..) => {
249 let def
= self.create_def(expr
.id
,
250 DefPathData
::ClosureExpr
,
252 self.parent_def
= Some(def
);
257 visit
::walk_expr(self, expr
);
258 self.parent_def
= parent_def
;
261 fn visit_ty(&mut self, ty
: &'a Ty
) {
263 TyKind
::Mac(..) => return self.visit_macro_invoc(ty
.id
, false),
264 TyKind
::Array(_
, ref length
) => self.visit_const_expr(length
),
265 TyKind
::ImplTrait(..) => {
266 self.create_def(ty
.id
, DefPathData
::ImplTrait
, REGULAR_SPACE
);
268 TyKind
::Typeof(ref expr
) => self.visit_const_expr(expr
),
271 visit
::walk_ty(self, ty
);
274 fn visit_lifetime_def(&mut self, def
: &'a LifetimeDef
) {
275 self.create_def(def
.lifetime
.id
,
276 DefPathData
::LifetimeDef(def
.lifetime
.ident
.name
.as_str()),
280 fn visit_stmt(&mut self, stmt
: &'a Stmt
) {
282 StmtKind
::Mac(..) => self.visit_macro_invoc(stmt
.id
, false),
283 _
=> visit
::walk_stmt(self, stmt
),