1 // Copyright 2012-2014 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.
18 use visit
::{FnKind, Visitor}
;
24 pub fn path_name_i(idents
: &[Ident
]) -> String
{
25 // FIXME: Bad copies (#2543 -- same for everything else that says "bad")
26 idents
.iter().map(|i
| i
.to_string()).collect
::<Vec
<String
>>().join("::")
29 pub fn is_path(e
: P
<Expr
>) -> bool
{
30 match e
.node { ExprKind::Path(..) => true, _ => false }
34 // convert a span and an identifier to the corresponding
36 pub fn ident_to_path(s
: Span
, identifier
: Ident
) -> Path
{
42 identifier
: identifier
,
43 parameters
: ast
::PathParameters
::AngleBracketed(ast
::AngleBracketedParameterData
{
44 lifetimes
: Vec
::new(),
53 // If path is a single segment ident path, return that ident. Otherwise, return
55 pub fn path_to_ident(path
: &Path
) -> Option
<Ident
> {
56 if path
.segments
.len() != 1 {
60 let segment
= &path
.segments
[0];
61 if !segment
.parameters
.is_empty() {
65 Some(segment
.identifier
)
68 pub fn ident_to_pat(id
: NodeId
, s
: Span
, i
: Ident
) -> P
<Pat
> {
69 let spanned
= codemap
::Spanned{ span: s, node: i }
;
72 node
: PatKind
::Ident(BindingMode
::ByValue(Mutability
::Immutable
), spanned
, None
),
77 /// Generate a "pretty" name for an `impl` from its type and trait.
78 /// This is designed so that symbols of `impl`'d methods give some
79 /// hint of where they came from, (previously they would all just be
80 /// listed as `__extensions__::method_name::hash`, with no indication
82 pub fn impl_pretty_name(trait_ref
: &Option
<TraitRef
>, ty
: Option
<&Ty
>) -> Ident
{
83 let mut pretty
= match ty
{
84 Some(t
) => pprust
::ty_to_string(t
),
85 None
=> String
::from("..")
89 Some(ref trait_ref
) => {
91 pretty
.push_str(&pprust
::path_to_string(&trait_ref
.path
));
95 token
::gensym_ident(&pretty
[..])
98 pub fn struct_field_visibility(field
: ast
::StructField
) -> Visibility
{
99 match field
.node
.kind
{
100 ast
::NamedField(_
, v
) | ast
::UnnamedField(v
) => v
104 // ______________________________________________________________________
105 // Enumerating the IDs which appear in an AST
107 #[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug)]
114 pub fn max() -> IdRange
{
121 pub fn empty(&self) -> bool
{
125 pub fn add(&mut self, id
: NodeId
) {
126 self.min
= cmp
::min(self.min
, id
);
127 self.max
= cmp
::max(self.max
, id
+ 1);
131 pub trait IdVisitingOperation
{
132 fn visit_id(&mut self, node_id
: NodeId
);
135 /// A visitor that applies its operation to all of the node IDs
136 /// in a visitable thing.
138 pub struct IdVisitor
<'a
, O
:'a
> {
139 pub operation
: &'a
mut O
,
140 pub visited_outermost
: bool
,
143 impl<'a
, O
: IdVisitingOperation
> IdVisitor
<'a
, O
> {
144 fn visit_generics_helper(&mut self, generics
: &Generics
) {
145 for type_parameter
in generics
.ty_params
.iter() {
146 self.operation
.visit_id(type_parameter
.id
)
148 for lifetime
in &generics
.lifetimes
{
149 self.operation
.visit_id(lifetime
.lifetime
.id
)
154 impl<'a
, 'v
, O
: IdVisitingOperation
> Visitor
<'v
> for IdVisitor
<'a
, O
> {
155 fn visit_mod(&mut self,
159 self.operation
.visit_id(node_id
);
160 visit
::walk_mod(self, module
)
163 fn visit_foreign_item(&mut self, foreign_item
: &ForeignItem
) {
164 self.operation
.visit_id(foreign_item
.id
);
165 visit
::walk_foreign_item(self, foreign_item
)
168 fn visit_item(&mut self, item
: &Item
) {
169 if self.visited_outermost
{
172 self.visited_outermost
= true
175 self.operation
.visit_id(item
.id
);
177 ItemKind
::Use(ref view_path
) => {
178 match view_path
.node
{
179 ViewPathSimple(_
, _
) |
180 ViewPathGlob(_
) => {}
181 ViewPathList(_
, ref paths
) => {
183 self.operation
.visit_id(path
.node
.id())
191 visit
::walk_item(self, item
);
193 self.visited_outermost
= false
196 fn visit_local(&mut self, local
: &Local
) {
197 self.operation
.visit_id(local
.id
);
198 visit
::walk_local(self, local
)
201 fn visit_block(&mut self, block
: &Block
) {
202 self.operation
.visit_id(block
.id
);
203 visit
::walk_block(self, block
)
206 fn visit_stmt(&mut self, statement
: &Stmt
) {
208 .visit_id(statement
.node
.id().expect("attempted to visit unexpanded stmt"));
209 visit
::walk_stmt(self, statement
)
212 fn visit_pat(&mut self, pattern
: &Pat
) {
213 self.operation
.visit_id(pattern
.id
);
214 visit
::walk_pat(self, pattern
)
217 fn visit_expr(&mut self, expression
: &Expr
) {
218 self.operation
.visit_id(expression
.id
);
219 visit
::walk_expr(self, expression
)
222 fn visit_ty(&mut self, typ
: &Ty
) {
223 self.operation
.visit_id(typ
.id
);
224 visit
::walk_ty(self, typ
)
227 fn visit_generics(&mut self, generics
: &Generics
) {
228 self.visit_generics_helper(generics
);
229 visit
::walk_generics(self, generics
)
232 fn visit_fn(&mut self,
233 function_kind
: visit
::FnKind
<'v
>,
234 function_declaration
: &'v FnDecl
,
238 match function_kind
{
239 FnKind
::Method(..) if self.visited_outermost
=> return,
240 FnKind
::Method(..) => self.visited_outermost
= true,
244 self.operation
.visit_id(node_id
);
246 match function_kind
{
247 FnKind
::ItemFn(_
, generics
, _
, _
, _
, _
) => {
248 self.visit_generics_helper(generics
)
250 FnKind
::Method(_
, sig
, _
) => {
251 self.visit_generics_helper(&sig
.generics
)
253 FnKind
::Closure
=> {}
256 for argument
in &function_declaration
.inputs
{
257 self.operation
.visit_id(argument
.id
)
262 function_declaration
,
266 if let FnKind
::Method(..) = function_kind
{
267 self.visited_outermost
= false;
271 fn visit_struct_field(&mut self, struct_field
: &StructField
) {
272 self.operation
.visit_id(struct_field
.node
.id
);
273 visit
::walk_struct_field(self, struct_field
)
276 fn visit_variant_data(&mut self,
277 struct_def
: &VariantData
,
282 self.operation
.visit_id(struct_def
.id());
283 visit
::walk_struct_def(self, struct_def
);
286 fn visit_trait_item(&mut self, ti
: &ast
::TraitItem
) {
287 self.operation
.visit_id(ti
.id
);
288 visit
::walk_trait_item(self, ti
);
291 fn visit_impl_item(&mut self, ii
: &ast
::ImplItem
) {
292 self.operation
.visit_id(ii
.id
);
293 visit
::walk_impl_item(self, ii
);
296 fn visit_lifetime(&mut self, lifetime
: &Lifetime
) {
297 self.operation
.visit_id(lifetime
.id
);
300 fn visit_lifetime_def(&mut self, def
: &LifetimeDef
) {
301 self.visit_lifetime(&def
.lifetime
);
304 fn visit_trait_ref(&mut self, trait_ref
: &TraitRef
) {
305 self.operation
.visit_id(trait_ref
.ref_id
);
306 visit
::walk_trait_ref(self, trait_ref
);
310 pub struct IdRangeComputingVisitor
{
314 impl IdRangeComputingVisitor
{
315 pub fn new() -> IdRangeComputingVisitor
{
316 IdRangeComputingVisitor { result: IdRange::max() }
319 pub fn result(&self) -> IdRange
{
324 impl IdVisitingOperation
for IdRangeComputingVisitor
{
325 fn visit_id(&mut self, id
: NodeId
) {
330 /// Computes the id range for a single fn body, ignoring nested items.
331 pub fn compute_id_range_for_fn_body(fk
: FnKind
,
338 let mut visitor
= IdRangeComputingVisitor
::new();
339 let mut id_visitor
= IdVisitor
{
340 operation
: &mut visitor
,
341 visited_outermost
: false,
343 id_visitor
.visit_fn(fk
, decl
, body
, sp
, id
);
344 id_visitor
.operation
.result
347 /// Returns true if the given pattern consists solely of an identifier
348 /// and false otherwise.
349 pub fn pat_is_ident(pat
: P
<ast
::Pat
>) -> bool
{
351 PatKind
::Ident(..) => true,
356 // are two paths equal when compared unhygienically?
357 // since I'm using this to replace ==, it seems appropriate
358 // to compare the span, global, etc. fields as well.
359 pub fn path_name_eq(a
: &ast
::Path
, b
: &ast
::Path
) -> bool
{
360 (a
.span
.source_equal(&b
.span
))
361 && (a
.global
== b
.global
)
362 && (segments_name_eq(&a
.segments
[..], &b
.segments
[..]))
365 // are two arrays of segments equal when compared unhygienically?
366 pub fn segments_name_eq(a
: &[ast
::PathSegment
], b
: &[ast
::PathSegment
]) -> bool
{
367 a
.len() == b
.len() &&
368 a
.iter().zip(b
).all(|(s
, t
)| {
369 s
.identifier
.name
== t
.identifier
.name
&&
370 // FIXME #7743: ident -> name problems in lifetime comparison?
371 // can types contain idents?
372 s
.parameters
== t
.parameters
381 fn ident_to_segment(id
: Ident
) -> PathSegment
{
382 PathSegment
{identifier
: id
,
383 parameters
: PathParameters
::none()}
386 #[test] fn idents_name_eq_test() {
387 assert
!(segments_name_eq(
388 &[Ident
::new(Name(3),SyntaxContext(4)), Ident
::new(Name(78),SyntaxContext(82))]
389 .iter().cloned().map(ident_to_segment
).collect
::<Vec
<PathSegment
>>(),
390 &[Ident
::new(Name(3),SyntaxContext(104)), Ident
::new(Name(78),SyntaxContext(182))]
391 .iter().cloned().map(ident_to_segment
).collect
::<Vec
<PathSegment
>>()));
392 assert
!(!segments_name_eq(
393 &[Ident
::new(Name(3),SyntaxContext(4)), Ident
::new(Name(78),SyntaxContext(82))]
394 .iter().cloned().map(ident_to_segment
).collect
::<Vec
<PathSegment
>>(),
395 &[Ident
::new(Name(3),SyntaxContext(104)), Ident
::new(Name(77),SyntaxContext(182))]
396 .iter().cloned().map(ident_to_segment
).collect
::<Vec
<PathSegment
>>()));