2014-02-05 17:31:33 +13:00
|
|
|
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
|
|
|
//! Output a CSV file containing the output from rustc's analysis. The data is
|
|
|
|
//! primarily designed to be used as input to the DXR tool, specifically its
|
|
|
|
//! Rust plugin. It could also be used by IDEs or other code browsing, search, or
|
|
|
|
//! cross-referencing tools.
|
|
|
|
//!
|
|
|
|
//! Dumping the analysis is implemented by walking the AST and getting a bunch of
|
|
|
|
//! info out from all over the place. We use Def IDs to identify objects. The
|
|
|
|
//! tricky part is getting syntactic (span, source text) and semantic (reference
|
|
|
|
//! Def IDs) information for parts of expressions which the compiler has discarded.
|
|
|
|
//! E.g., in a path `foo::bar::baz`, the compiler only keeps a span for the whole
|
|
|
|
//! path and a reference to `baz`, but we want spans and references for all three
|
|
|
|
//! idents.
|
|
|
|
//!
|
|
|
|
//! SpanUtils is used to manipulate spans. In particular, to extract sub-spans
|
|
|
|
//! from spans (e.g., the span for `bar` from the above example path).
|
|
|
|
//! Recorder is used for recording the output in csv format. FmtStrs separates
|
|
|
|
//! the format of the output away from extracting it from the compiler.
|
|
|
|
//! DxrVisitor walks the AST and processes it.
|
|
|
|
|
|
|
|
use driver::driver::CrateAnalysis;
|
|
|
|
use driver::session::Session;
|
|
|
|
|
|
|
|
use middle::def;
|
|
|
|
use middle::ty;
|
|
|
|
use middle::typeck;
|
|
|
|
|
|
|
|
use std::cell::Cell;
|
|
|
|
use std::io;
|
|
|
|
use std::io::File;
|
|
|
|
use std::io::fs;
|
|
|
|
use std::os;
|
|
|
|
|
|
|
|
use syntax::ast;
|
|
|
|
use syntax::ast_util;
|
2014-07-14 16:31:52 -07:00
|
|
|
use syntax::ast_util::PostExpansionMethod;
|
2014-02-05 17:31:33 +13:00
|
|
|
use syntax::ast::{NodeId,DefId};
|
|
|
|
use syntax::ast_map::NodeItem;
|
|
|
|
use syntax::attr;
|
|
|
|
use syntax::codemap::*;
|
|
|
|
use syntax::parse::token;
|
|
|
|
use syntax::parse::token::{get_ident,keywords};
|
2014-08-27 21:46:52 -04:00
|
|
|
use syntax::owned_slice::OwnedSlice;
|
2014-02-05 17:31:33 +13:00
|
|
|
use syntax::visit;
|
|
|
|
use syntax::visit::Visitor;
|
2014-06-21 03:39:03 -07:00
|
|
|
use syntax::print::pprust::{path_to_string,ty_to_string};
|
2014-09-07 20:09:06 +03:00
|
|
|
use syntax::ptr::P;
|
2014-02-05 17:31:33 +13:00
|
|
|
|
|
|
|
use middle::save::span_utils::SpanUtils;
|
|
|
|
use middle::save::recorder::Recorder;
|
|
|
|
use middle::save::recorder::FmtStrs;
|
|
|
|
|
|
|
|
use util::ppaux;
|
|
|
|
|
|
|
|
mod span_utils;
|
|
|
|
mod recorder;
|
|
|
|
|
|
|
|
// Helper function to escape quotes in a string
|
|
|
|
fn escape(s: String) -> String {
|
|
|
|
s.replace("\"", "\"\"")
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the expression is a macro expansion or other generated code, run screaming and don't index.
|
|
|
|
fn generated_code(span: Span) -> bool {
|
2014-09-16 22:46:38 +03:00
|
|
|
span.expn_id != NO_EXPANSION || span == DUMMY_SP
|
2014-02-05 17:31:33 +13:00
|
|
|
}
|
|
|
|
|
2014-04-22 15:56:37 +03:00
|
|
|
struct DxrVisitor<'l, 'tcx: 'l> {
|
2014-02-05 17:31:33 +13:00
|
|
|
sess: &'l Session,
|
2014-04-22 15:56:37 +03:00
|
|
|
analysis: &'l CrateAnalysis<'tcx>,
|
2014-02-05 17:31:33 +13:00
|
|
|
|
|
|
|
collected_paths: Vec<(NodeId, ast::Path, bool, recorder::Row)>,
|
|
|
|
collecting: bool,
|
|
|
|
|
|
|
|
span: SpanUtils<'l>,
|
|
|
|
fmt: FmtStrs<'l>,
|
2014-09-12 13:10:30 +03:00
|
|
|
|
|
|
|
cur_scope: NodeId
|
2014-02-05 17:31:33 +13:00
|
|
|
}
|
|
|
|
|
2014-04-22 15:56:37 +03:00
|
|
|
impl <'l, 'tcx> DxrVisitor<'l, 'tcx> {
|
2014-09-12 13:10:30 +03:00
|
|
|
fn nest(&mut self, scope_id: NodeId, f: |&mut DxrVisitor<'l, 'tcx>|) {
|
|
|
|
let parent_scope = self.cur_scope;
|
|
|
|
self.cur_scope = scope_id;
|
|
|
|
f(self);
|
|
|
|
self.cur_scope = parent_scope;
|
|
|
|
}
|
|
|
|
|
2014-02-05 17:31:33 +13:00
|
|
|
fn dump_crate_info(&mut self, name: &str, krate: &ast::Crate) {
|
|
|
|
// the current crate
|
|
|
|
self.fmt.crate_str(krate.span, name);
|
|
|
|
|
|
|
|
// dump info about all the external crates referenced from this crate
|
|
|
|
self.sess.cstore.iter_crate_data(|n, cmd| {
|
|
|
|
self.fmt.external_crate_str(krate.span, cmd.name.as_slice(), n);
|
|
|
|
});
|
|
|
|
self.fmt.recorder.record("end_external_crates\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return all non-empty prefixes of a path.
|
|
|
|
// For each prefix, we return the span for the last segment in the prefix and
|
|
|
|
// a str representation of the entire prefix.
|
|
|
|
fn process_path_prefixes(&self, path: &ast::Path) -> Vec<(Span, String)> {
|
|
|
|
let spans = self.span.spans_for_path_segments(path);
|
|
|
|
|
|
|
|
// Paths to enums seem to not match their spans - the span includes all the
|
|
|
|
// variants too. But they seem to always be at the end, so I hope we can cope with
|
|
|
|
// always using the first ones. So, only error out if we don't have enough spans.
|
|
|
|
// What could go wrong...?
|
|
|
|
if spans.len() < path.segments.len() {
|
|
|
|
error!("Mis-calculated spans for path '{}'. \
|
|
|
|
Found {} spans, expected {}. Found spans:",
|
2014-06-21 03:39:03 -07:00
|
|
|
path_to_string(path), spans.len(), path.segments.len());
|
2014-02-05 17:31:33 +13:00
|
|
|
for s in spans.iter() {
|
|
|
|
let loc = self.sess.codemap().lookup_char_pos(s.lo);
|
|
|
|
error!(" '{}' in {}, line {}",
|
|
|
|
self.span.snippet(*s), loc.file.name, loc.line);
|
|
|
|
}
|
|
|
|
return vec!();
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut result: Vec<(Span, String)> = vec!();
|
|
|
|
|
|
|
|
|
|
|
|
let mut segs = vec!();
|
|
|
|
for (seg, span) in path.segments.iter().zip(spans.iter()) {
|
|
|
|
segs.push(seg.clone());
|
|
|
|
let sub_path = ast::Path{span: *span, // span for the last segment
|
|
|
|
global: path.global,
|
|
|
|
segments: segs};
|
2014-06-21 03:39:03 -07:00
|
|
|
let qualname = path_to_string(&sub_path);
|
2014-02-05 17:31:33 +13:00
|
|
|
result.push((*span, qualname));
|
|
|
|
segs = sub_path.segments;
|
|
|
|
}
|
|
|
|
|
|
|
|
result
|
|
|
|
}
|
|
|
|
|
2014-09-12 13:10:30 +03:00
|
|
|
fn write_sub_paths(&mut self, path: &ast::Path) {
|
2014-02-05 17:31:33 +13:00
|
|
|
let sub_paths = self.process_path_prefixes(path);
|
|
|
|
for &(ref span, ref qualname) in sub_paths.iter() {
|
|
|
|
self.fmt.sub_mod_ref_str(path.span,
|
|
|
|
*span,
|
|
|
|
qualname.as_slice(),
|
2014-09-12 13:10:30 +03:00
|
|
|
self.cur_scope);
|
2014-02-05 17:31:33 +13:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// As write_sub_paths, but does not process the last ident in the path (assuming it
|
|
|
|
// will be processed elsewhere).
|
2014-09-12 13:10:30 +03:00
|
|
|
fn write_sub_paths_truncated(&mut self, path: &ast::Path) {
|
2014-02-05 17:31:33 +13:00
|
|
|
let sub_paths = self.process_path_prefixes(path);
|
|
|
|
let len = sub_paths.len();
|
|
|
|
if len <= 1 {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
let sub_paths = sub_paths.slice(0, len-1);
|
|
|
|
for &(ref span, ref qualname) in sub_paths.iter() {
|
|
|
|
self.fmt.sub_mod_ref_str(path.span,
|
|
|
|
*span,
|
|
|
|
qualname.as_slice(),
|
2014-09-12 13:10:30 +03:00
|
|
|
self.cur_scope);
|
2014-02-05 17:31:33 +13:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// As write_sub_paths, but expects a path of the form module_path::trait::method
|
|
|
|
// Where trait could actually be a struct too.
|
2014-09-12 13:10:30 +03:00
|
|
|
fn write_sub_path_trait_truncated(&mut self, path: &ast::Path) {
|
2014-02-05 17:31:33 +13:00
|
|
|
let sub_paths = self.process_path_prefixes(path);
|
|
|
|
let len = sub_paths.len();
|
|
|
|
if len <= 1 {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
let sub_paths = sub_paths.slice_to(len-1);
|
|
|
|
|
|
|
|
// write the trait part of the sub-path
|
|
|
|
let (ref span, ref qualname) = sub_paths[len-2];
|
|
|
|
self.fmt.sub_type_ref_str(path.span,
|
|
|
|
*span,
|
|
|
|
qualname.as_slice());
|
|
|
|
|
|
|
|
// write the other sub-paths
|
|
|
|
if len <= 2 {
|
|
|
|
return;
|
|
|
|
}
|
2014-09-24 23:41:09 +12:00
|
|
|
let sub_paths = sub_paths[..len-2];
|
2014-02-05 17:31:33 +13:00
|
|
|
for &(ref span, ref qualname) in sub_paths.iter() {
|
|
|
|
self.fmt.sub_mod_ref_str(path.span,
|
|
|
|
*span,
|
|
|
|
qualname.as_slice(),
|
2014-09-12 13:10:30 +03:00
|
|
|
self.cur_scope);
|
2014-02-05 17:31:33 +13:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// looks up anything, not just a type
|
|
|
|
fn lookup_type_ref(&self, ref_id: NodeId) -> Option<DefId> {
|
|
|
|
if !self.analysis.ty_cx.def_map.borrow().contains_key(&ref_id) {
|
|
|
|
self.sess.bug(format!("def_map has no key for {} in lookup_type_ref",
|
|
|
|
ref_id).as_slice());
|
|
|
|
}
|
2014-10-14 23:05:01 -07:00
|
|
|
let def = (*self.analysis.ty_cx.def_map.borrow())[ref_id];
|
2014-02-05 17:31:33 +13:00
|
|
|
match def {
|
|
|
|
def::DefPrimTy(_) => None,
|
|
|
|
_ => Some(def.def_id()),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn lookup_def_kind(&self, ref_id: NodeId, span: Span) -> Option<recorder::Row> {
|
|
|
|
let def_map = self.analysis.ty_cx.def_map.borrow();
|
|
|
|
if !def_map.contains_key(&ref_id) {
|
|
|
|
self.sess.span_bug(span, format!("def_map has no key for {} in lookup_def_kind",
|
|
|
|
ref_id).as_slice());
|
|
|
|
}
|
2014-10-14 23:05:01 -07:00
|
|
|
let def = (*def_map)[ref_id];
|
2014-02-05 17:31:33 +13:00
|
|
|
match def {
|
|
|
|
def::DefMod(_) |
|
|
|
|
def::DefForeignMod(_) => Some(recorder::ModRef),
|
|
|
|
def::DefStruct(_) => Some(recorder::StructRef),
|
2014-09-16 09:13:00 +12:00
|
|
|
def::DefTy(..) |
|
2014-08-05 19:44:21 -07:00
|
|
|
def::DefAssociatedTy(..) |
|
2014-02-05 17:31:33 +13:00
|
|
|
def::DefTrait(_) => Some(recorder::TypeRef),
|
|
|
|
def::DefStatic(_, _) |
|
rustc: Add `const` globals to the language
This change is an implementation of [RFC 69][rfc] which adds a third kind of
global to the language, `const`. This global is most similar to what the old
`static` was, and if you're unsure about what to use then you should use a
`const`.
The semantics of these three kinds of globals are:
* A `const` does not represent a memory location, but only a value. Constants
are translated as rvalues, which means that their values are directly inlined
at usage location (similar to a #define in C/C++). Constant values are, well,
constant, and can not be modified. Any "modification" is actually a
modification to a local value on the stack rather than the actual constant
itself.
Almost all values are allowed inside constants, whether they have interior
mutability or not. There are a few minor restrictions listed in the RFC, but
they should in general not come up too often.
* A `static` now always represents a memory location (unconditionally). Any
references to the same `static` are actually a reference to the same memory
location. Only values whose types ascribe to `Sync` are allowed in a `static`.
This restriction is in place because many threads may access a `static`
concurrently. Lifting this restriction (and allowing unsafe access) is a
future extension not implemented at this time.
* A `static mut` continues to always represent a memory location. All references
to a `static mut` continue to be `unsafe`.
This is a large breaking change, and many programs will need to be updated
accordingly. A summary of the breaking changes is:
* Statics may no longer be used in patterns. Statics now always represent a
memory location, which can sometimes be modified. To fix code, repurpose the
matched-on-`static` to a `const`.
static FOO: uint = 4;
match n {
FOO => { /* ... */ }
_ => { /* ... */ }
}
change this code to:
const FOO: uint = 4;
match n {
FOO => { /* ... */ }
_ => { /* ... */ }
}
* Statics may no longer refer to other statics by value. Due to statics being
able to change at runtime, allowing them to reference one another could
possibly lead to confusing semantics. If you are in this situation, use a
constant initializer instead. Note, however, that statics may reference other
statics by address, however.
* Statics may no longer be used in constant expressions, such as array lengths.
This is due to the same restrictions as listed above. Use a `const` instead.
[breaking-change]
[rfc]: https://github.com/rust-lang/rfcs/pull/246
2014-10-06 08:17:01 -07:00
|
|
|
def::DefConst(_) |
|
2014-09-17 18:17:09 +03:00
|
|
|
def::DefLocal(_) |
|
2014-02-05 17:31:33 +13:00
|
|
|
def::DefVariant(_, _, _) |
|
2014-09-15 00:40:45 +03:00
|
|
|
def::DefUpvar(..) => Some(recorder::VarRef),
|
2014-02-05 17:31:33 +13:00
|
|
|
|
2014-09-29 18:27:07 +02:00
|
|
|
def::DefFn(..) => Some(recorder::FnRef),
|
2014-02-05 17:31:33 +13:00
|
|
|
|
|
|
|
def::DefSelfTy(_) |
|
|
|
|
def::DefRegion(_) |
|
|
|
|
def::DefTyParamBinder(_) |
|
|
|
|
def::DefLabel(_) |
|
2014-10-16 17:44:24 +13:00
|
|
|
def::DefStaticMethod(..) |
|
2014-05-31 18:53:13 -04:00
|
|
|
def::DefTyParam(..) |
|
2014-02-05 17:31:33 +13:00
|
|
|
def::DefUse(_) |
|
2014-10-15 13:33:20 +13:00
|
|
|
def::DefMethod(..) |
|
2014-02-05 17:31:33 +13:00
|
|
|
def::DefPrimTy(_) => {
|
2014-10-15 02:25:34 -04:00
|
|
|
self.sess.span_bug(span, format!("lookup_def_kind for unexpected item: {}",
|
2014-02-05 17:31:33 +13:00
|
|
|
def).as_slice());
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-12 13:10:30 +03:00
|
|
|
fn process_formals(&mut self, formals: &Vec<ast::Arg>, qualname: &str) {
|
2014-02-05 17:31:33 +13:00
|
|
|
for arg in formals.iter() {
|
|
|
|
assert!(self.collected_paths.len() == 0 && !self.collecting);
|
|
|
|
self.collecting = true;
|
2014-09-12 13:10:30 +03:00
|
|
|
self.visit_pat(&*arg.pat);
|
2014-02-05 17:31:33 +13:00
|
|
|
self.collecting = false;
|
|
|
|
let span_utils = self.span;
|
|
|
|
for &(id, ref p, _, _) in self.collected_paths.iter() {
|
2014-06-21 03:39:03 -07:00
|
|
|
let typ = ppaux::ty_to_string(&self.analysis.ty_cx,
|
2014-11-10 00:59:56 +02:00
|
|
|
(*self.analysis.ty_cx.node_types.borrow())[id]);
|
2014-02-05 17:31:33 +13:00
|
|
|
// get the span only for the name of the variable (I hope the path is only ever a
|
|
|
|
// variable name, but who knows?)
|
|
|
|
self.fmt.formal_str(p.span,
|
|
|
|
span_utils.span_for_last_ident(p.span),
|
|
|
|
id,
|
|
|
|
qualname,
|
2014-06-21 03:39:03 -07:00
|
|
|
path_to_string(p).as_slice(),
|
2014-02-05 17:31:33 +13:00
|
|
|
typ.as_slice());
|
|
|
|
}
|
|
|
|
self.collected_paths.clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-12 13:10:30 +03:00
|
|
|
fn process_method(&mut self, method: &ast::Method) {
|
2014-02-05 17:31:33 +13:00
|
|
|
if generated_code(method.span) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut scope_id;
|
|
|
|
// The qualname for a method is the trait name or name of the struct in an impl in
|
|
|
|
// which the method is declared in followed by the method's name.
|
|
|
|
let mut qualname = match ty::impl_of_method(&self.analysis.ty_cx,
|
|
|
|
ast_util::local_def(method.id)) {
|
|
|
|
Some(impl_id) => match self.analysis.ty_cx.map.get(impl_id.node) {
|
|
|
|
NodeItem(item) => {
|
|
|
|
scope_id = item.id;
|
|
|
|
match item.node {
|
2014-09-07 20:09:06 +03:00
|
|
|
ast::ItemImpl(_, _, ref ty, _) => {
|
2014-02-05 17:31:33 +13:00
|
|
|
let mut result = String::from_str("<");
|
2014-09-07 20:09:06 +03:00
|
|
|
result.push_str(ty_to_string(&**ty).as_slice());
|
2014-02-05 17:31:33 +13:00
|
|
|
|
2014-08-04 13:56:56 -07:00
|
|
|
match ty::trait_of_item(&self.analysis.ty_cx,
|
|
|
|
ast_util::local_def(method.id)) {
|
2014-02-05 17:31:33 +13:00
|
|
|
Some(def_id) => {
|
|
|
|
result.push_str(" as ");
|
|
|
|
result.push_str(
|
|
|
|
ty::item_path_str(&self.analysis.ty_cx, def_id).as_slice());
|
|
|
|
},
|
|
|
|
None => {}
|
|
|
|
}
|
2014-10-14 23:05:01 -07:00
|
|
|
result.push_str(">::");
|
|
|
|
result
|
2014-02-05 17:31:33 +13:00
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
self.sess.span_bug(method.span,
|
|
|
|
format!("Container {} for method {} not an impl?",
|
|
|
|
impl_id.node, method.id).as_slice());
|
|
|
|
},
|
|
|
|
}
|
|
|
|
},
|
|
|
|
_ => {
|
|
|
|
self.sess.span_bug(method.span,
|
2014-10-15 02:25:34 -04:00
|
|
|
format!("Container {} for method {} is not a node item {}",
|
2014-02-05 17:31:33 +13:00
|
|
|
impl_id.node,
|
|
|
|
method.id,
|
|
|
|
self.analysis.ty_cx.map.get(impl_id.node)
|
|
|
|
).as_slice());
|
|
|
|
},
|
|
|
|
},
|
2014-08-04 13:56:56 -07:00
|
|
|
None => match ty::trait_of_item(&self.analysis.ty_cx,
|
|
|
|
ast_util::local_def(method.id)) {
|
2014-02-05 17:31:33 +13:00
|
|
|
Some(def_id) => {
|
|
|
|
scope_id = def_id.node;
|
|
|
|
match self.analysis.ty_cx.map.get(def_id.node) {
|
|
|
|
NodeItem(_) => {
|
2014-10-14 23:05:01 -07:00
|
|
|
let mut result = ty::item_path_str(&self.analysis.ty_cx, def_id);
|
|
|
|
result.push_str("::");
|
|
|
|
result
|
2014-02-05 17:31:33 +13:00
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
self.sess.span_bug(method.span,
|
|
|
|
format!("Could not find container {} for method {}",
|
|
|
|
def_id.node, method.id).as_slice());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
None => {
|
|
|
|
self.sess.span_bug(method.span,
|
|
|
|
format!("Could not find container for method {}",
|
|
|
|
method.id).as_slice());
|
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2014-07-14 16:31:52 -07:00
|
|
|
qualname.push_str(get_ident(method.pe_ident()).get());
|
2014-02-05 17:31:33 +13:00
|
|
|
let qualname = qualname.as_slice();
|
|
|
|
|
|
|
|
// record the decl for this def (if it has one)
|
2014-08-04 13:56:56 -07:00
|
|
|
let decl_id = ty::trait_item_of_item(&self.analysis.ty_cx,
|
|
|
|
ast_util::local_def(method.id))
|
2014-10-14 23:05:01 -07:00
|
|
|
.and_then(|def_id| {
|
|
|
|
if match def_id {
|
2014-08-04 13:56:56 -07:00
|
|
|
ty::MethodTraitItemId(def_id) => {
|
|
|
|
method.id != 0 && def_id.node == 0
|
|
|
|
}
|
2014-08-05 19:44:21 -07:00
|
|
|
ty::TypeTraitItemId(_) => false,
|
2014-10-14 23:05:01 -07:00
|
|
|
} {
|
|
|
|
Some(def_id)
|
|
|
|
} else {
|
|
|
|
None
|
2014-08-04 13:56:56 -07:00
|
|
|
}
|
|
|
|
});
|
|
|
|
let decl_id = match decl_id {
|
|
|
|
None => None,
|
2014-08-05 19:44:21 -07:00
|
|
|
Some(id) => Some(id.def_id()),
|
2014-08-04 13:56:56 -07:00
|
|
|
};
|
2014-02-05 17:31:33 +13:00
|
|
|
|
|
|
|
let sub_span = self.span.sub_span_after_keyword(method.span, keywords::Fn);
|
|
|
|
self.fmt.method_str(method.span,
|
|
|
|
sub_span,
|
|
|
|
method.id,
|
|
|
|
qualname,
|
|
|
|
decl_id,
|
|
|
|
scope_id);
|
|
|
|
|
2014-09-12 13:10:30 +03:00
|
|
|
self.process_formals(&method.pe_fn_decl().inputs, qualname);
|
2014-02-05 17:31:33 +13:00
|
|
|
|
|
|
|
// walk arg and return types
|
2014-07-14 16:31:52 -07:00
|
|
|
for arg in method.pe_fn_decl().inputs.iter() {
|
2014-09-12 13:10:30 +03:00
|
|
|
self.visit_ty(&*arg.ty);
|
2014-02-05 17:31:33 +13:00
|
|
|
}
|
2014-11-09 16:14:15 +01:00
|
|
|
|
|
|
|
if let ast::Return(ref ret_ty) = method.pe_fn_decl().output {
|
|
|
|
self.visit_ty(&**ret_ty);
|
|
|
|
}
|
|
|
|
|
2014-02-05 17:31:33 +13:00
|
|
|
// walk the fn body
|
2014-09-12 13:10:30 +03:00
|
|
|
self.nest(method.id, |v| v.visit_block(&*method.pe_body()));
|
2014-02-05 17:31:33 +13:00
|
|
|
|
2014-07-14 16:31:52 -07:00
|
|
|
self.process_generic_params(method.pe_generics(),
|
2014-02-05 17:31:33 +13:00
|
|
|
method.span,
|
|
|
|
qualname,
|
2014-09-12 13:10:30 +03:00
|
|
|
method.id);
|
2014-02-05 17:31:33 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
fn process_trait_ref(&mut self,
|
|
|
|
trait_ref: &ast::TraitRef,
|
|
|
|
impl_id: Option<NodeId>) {
|
|
|
|
match self.lookup_type_ref(trait_ref.ref_id) {
|
|
|
|
Some(id) => {
|
|
|
|
let sub_span = self.span.sub_span_for_type_name(trait_ref.path.span);
|
|
|
|
self.fmt.ref_str(recorder::TypeRef,
|
|
|
|
trait_ref.path.span,
|
|
|
|
sub_span,
|
|
|
|
id,
|
2014-09-12 13:10:30 +03:00
|
|
|
self.cur_scope);
|
2014-02-05 17:31:33 +13:00
|
|
|
match impl_id {
|
|
|
|
Some(impl_id) => self.fmt.impl_str(trait_ref.path.span,
|
|
|
|
sub_span,
|
|
|
|
impl_id,
|
|
|
|
id,
|
2014-09-12 13:10:30 +03:00
|
|
|
self.cur_scope),
|
2014-02-05 17:31:33 +13:00
|
|
|
None => (),
|
|
|
|
}
|
2014-09-12 13:10:30 +03:00
|
|
|
visit::walk_path(self, &trait_ref.path);
|
2014-02-05 17:31:33 +13:00
|
|
|
},
|
|
|
|
None => ()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn process_struct_field_def(&mut self,
|
|
|
|
field: &ast::StructField,
|
|
|
|
qualname: &str,
|
|
|
|
scope_id: NodeId) {
|
|
|
|
match field.node.kind {
|
|
|
|
ast::NamedField(ident, _) => {
|
|
|
|
let name = get_ident(ident);
|
|
|
|
let qualname = format!("{}::{}", qualname, name);
|
2014-06-21 03:39:03 -07:00
|
|
|
let typ = ppaux::ty_to_string(&self.analysis.ty_cx,
|
2014-11-10 00:59:56 +02:00
|
|
|
(*self.analysis.ty_cx.node_types.borrow())[field.node.id]);
|
2014-10-27 19:22:52 +11:00
|
|
|
match self.span.sub_span_before_token(field.span, token::Colon) {
|
2014-02-05 17:31:33 +13:00
|
|
|
Some(sub_span) => self.fmt.field_str(field.span,
|
|
|
|
Some(sub_span),
|
|
|
|
field.node.id,
|
|
|
|
name.get().as_slice(),
|
|
|
|
qualname.as_slice(),
|
|
|
|
typ.as_slice(),
|
|
|
|
scope_id),
|
|
|
|
None => self.sess.span_bug(field.span,
|
|
|
|
format!("Could not find sub-span for field {}",
|
|
|
|
qualname).as_slice()),
|
|
|
|
}
|
|
|
|
},
|
|
|
|
_ => (),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Dump generic params bindings, then visit_generics
|
|
|
|
fn process_generic_params(&mut self, generics:&ast::Generics,
|
|
|
|
full_span: Span,
|
|
|
|
prefix: &str,
|
2014-09-12 13:10:30 +03:00
|
|
|
id: NodeId) {
|
2014-02-05 17:31:33 +13:00
|
|
|
// We can't only use visit_generics since we don't have spans for param
|
|
|
|
// bindings, so we reparse the full_span to get those sub spans.
|
|
|
|
// However full span is the entire enum/fn/struct block, so we only want
|
|
|
|
// the first few to match the number of generics we're looking for.
|
|
|
|
let param_sub_spans = self.span.spans_for_ty_params(full_span,
|
|
|
|
(generics.ty_params.len() as int));
|
|
|
|
for (param, param_ss) in generics.ty_params.iter().zip(param_sub_spans.iter()) {
|
|
|
|
// Append $id to name to make sure each one is unique
|
|
|
|
let name = format!("{}::{}${}",
|
|
|
|
prefix,
|
|
|
|
escape(self.span.snippet(*param_ss)),
|
|
|
|
id);
|
|
|
|
self.fmt.typedef_str(full_span,
|
|
|
|
Some(*param_ss),
|
|
|
|
param.id,
|
|
|
|
name.as_slice(),
|
|
|
|
"");
|
|
|
|
}
|
2014-09-12 13:10:30 +03:00
|
|
|
self.visit_generics(generics);
|
2014-02-05 17:31:33 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
fn process_fn(&mut self,
|
|
|
|
item: &ast::Item,
|
2014-09-07 20:09:06 +03:00
|
|
|
decl: &ast::FnDecl,
|
2014-02-05 17:31:33 +13:00
|
|
|
ty_params: &ast::Generics,
|
2014-09-07 20:09:06 +03:00
|
|
|
body: &ast::Block) {
|
2014-06-21 03:39:03 -07:00
|
|
|
let qualname = self.analysis.ty_cx.map.path_to_string(item.id);
|
2014-02-05 17:31:33 +13:00
|
|
|
|
|
|
|
let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Fn);
|
|
|
|
self.fmt.fn_str(item.span,
|
|
|
|
sub_span,
|
|
|
|
item.id,
|
|
|
|
qualname.as_slice(),
|
2014-09-12 13:10:30 +03:00
|
|
|
self.cur_scope);
|
2014-02-05 17:31:33 +13:00
|
|
|
|
2014-09-12 13:10:30 +03:00
|
|
|
self.process_formals(&decl.inputs, qualname.as_slice());
|
2014-02-05 17:31:33 +13:00
|
|
|
|
|
|
|
// walk arg and return types
|
|
|
|
for arg in decl.inputs.iter() {
|
2014-09-12 13:10:30 +03:00
|
|
|
self.visit_ty(&*arg.ty);
|
2014-02-05 17:31:33 +13:00
|
|
|
}
|
2014-11-09 16:14:15 +01:00
|
|
|
|
|
|
|
if let ast::Return(ref ret_ty) = decl.output {
|
|
|
|
self.visit_ty(&**ret_ty);
|
|
|
|
}
|
2014-02-05 17:31:33 +13:00
|
|
|
|
|
|
|
// walk the body
|
2014-09-12 13:10:30 +03:00
|
|
|
self.nest(item.id, |v| v.visit_block(&*body));
|
2014-02-05 17:31:33 +13:00
|
|
|
|
2014-09-12 13:10:30 +03:00
|
|
|
self.process_generic_params(ty_params, item.span, qualname.as_slice(), item.id);
|
2014-02-05 17:31:33 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
fn process_static(&mut self,
|
|
|
|
item: &ast::Item,
|
2014-09-07 20:09:06 +03:00
|
|
|
typ: &ast::Ty,
|
2014-02-05 17:31:33 +13:00
|
|
|
mt: ast::Mutability,
|
|
|
|
expr: &ast::Expr)
|
|
|
|
{
|
2014-06-21 03:39:03 -07:00
|
|
|
let qualname = self.analysis.ty_cx.map.path_to_string(item.id);
|
2014-02-05 17:31:33 +13:00
|
|
|
|
2014-07-02 21:27:07 -04:00
|
|
|
// If the variable is immutable, save the initialising expression.
|
2014-02-05 17:31:33 +13:00
|
|
|
let value = match mt {
|
|
|
|
ast::MutMutable => String::from_str("<mutable>"),
|
|
|
|
ast::MutImmutable => self.span.snippet(expr.span),
|
|
|
|
};
|
|
|
|
|
|
|
|
let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Static);
|
|
|
|
self.fmt.static_str(item.span,
|
|
|
|
sub_span,
|
|
|
|
item.id,
|
|
|
|
get_ident(item.ident).get(),
|
|
|
|
qualname.as_slice(),
|
|
|
|
value.as_slice(),
|
2014-06-21 03:39:03 -07:00
|
|
|
ty_to_string(&*typ).as_slice(),
|
2014-09-12 13:10:30 +03:00
|
|
|
self.cur_scope);
|
2014-02-05 17:31:33 +13:00
|
|
|
|
|
|
|
// walk type and init value
|
2014-09-12 13:10:30 +03:00
|
|
|
self.visit_ty(&*typ);
|
|
|
|
self.visit_expr(expr);
|
2014-02-05 17:31:33 +13:00
|
|
|
}
|
|
|
|
|
rustc: Add `const` globals to the language
This change is an implementation of [RFC 69][rfc] which adds a third kind of
global to the language, `const`. This global is most similar to what the old
`static` was, and if you're unsure about what to use then you should use a
`const`.
The semantics of these three kinds of globals are:
* A `const` does not represent a memory location, but only a value. Constants
are translated as rvalues, which means that their values are directly inlined
at usage location (similar to a #define in C/C++). Constant values are, well,
constant, and can not be modified. Any "modification" is actually a
modification to a local value on the stack rather than the actual constant
itself.
Almost all values are allowed inside constants, whether they have interior
mutability or not. There are a few minor restrictions listed in the RFC, but
they should in general not come up too often.
* A `static` now always represents a memory location (unconditionally). Any
references to the same `static` are actually a reference to the same memory
location. Only values whose types ascribe to `Sync` are allowed in a `static`.
This restriction is in place because many threads may access a `static`
concurrently. Lifting this restriction (and allowing unsafe access) is a
future extension not implemented at this time.
* A `static mut` continues to always represent a memory location. All references
to a `static mut` continue to be `unsafe`.
This is a large breaking change, and many programs will need to be updated
accordingly. A summary of the breaking changes is:
* Statics may no longer be used in patterns. Statics now always represent a
memory location, which can sometimes be modified. To fix code, repurpose the
matched-on-`static` to a `const`.
static FOO: uint = 4;
match n {
FOO => { /* ... */ }
_ => { /* ... */ }
}
change this code to:
const FOO: uint = 4;
match n {
FOO => { /* ... */ }
_ => { /* ... */ }
}
* Statics may no longer refer to other statics by value. Due to statics being
able to change at runtime, allowing them to reference one another could
possibly lead to confusing semantics. If you are in this situation, use a
constant initializer instead. Note, however, that statics may reference other
statics by address, however.
* Statics may no longer be used in constant expressions, such as array lengths.
This is due to the same restrictions as listed above. Use a `const` instead.
[breaking-change]
[rfc]: https://github.com/rust-lang/rfcs/pull/246
2014-10-06 08:17:01 -07:00
|
|
|
fn process_const(&mut self,
|
|
|
|
item: &ast::Item,
|
|
|
|
typ: &ast::Ty,
|
|
|
|
expr: &ast::Expr)
|
|
|
|
{
|
|
|
|
let qualname = self.analysis.ty_cx.map.path_to_string(item.id);
|
|
|
|
|
|
|
|
let sub_span = self.span.sub_span_after_keyword(item.span,
|
|
|
|
keywords::Const);
|
|
|
|
self.fmt.static_str(item.span,
|
|
|
|
sub_span,
|
|
|
|
item.id,
|
|
|
|
get_ident(item.ident).get(),
|
|
|
|
qualname.as_slice(),
|
|
|
|
"",
|
|
|
|
ty_to_string(&*typ).as_slice(),
|
|
|
|
self.cur_scope);
|
|
|
|
|
|
|
|
// walk type and init value
|
|
|
|
self.visit_ty(&*typ);
|
|
|
|
self.visit_expr(expr);
|
|
|
|
}
|
|
|
|
|
2014-02-05 17:31:33 +13:00
|
|
|
fn process_struct(&mut self,
|
|
|
|
item: &ast::Item,
|
|
|
|
def: &ast::StructDef,
|
|
|
|
ty_params: &ast::Generics) {
|
2014-06-21 03:39:03 -07:00
|
|
|
let qualname = self.analysis.ty_cx.map.path_to_string(item.id);
|
2014-02-05 17:31:33 +13:00
|
|
|
|
|
|
|
let ctor_id = match def.ctor_id {
|
|
|
|
Some(node_id) => node_id,
|
|
|
|
None => -1,
|
|
|
|
};
|
|
|
|
let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Struct);
|
|
|
|
self.fmt.struct_str(item.span,
|
|
|
|
sub_span,
|
|
|
|
item.id,
|
|
|
|
ctor_id,
|
|
|
|
qualname.as_slice(),
|
2014-09-12 13:10:30 +03:00
|
|
|
self.cur_scope);
|
2014-02-05 17:31:33 +13:00
|
|
|
|
|
|
|
// fields
|
|
|
|
for field in def.fields.iter() {
|
|
|
|
self.process_struct_field_def(field, qualname.as_slice(), item.id);
|
2014-09-12 13:10:30 +03:00
|
|
|
self.visit_ty(&*field.node.ty);
|
2014-02-05 17:31:33 +13:00
|
|
|
}
|
|
|
|
|
2014-09-12 13:10:30 +03:00
|
|
|
self.process_generic_params(ty_params, item.span, qualname.as_slice(), item.id);
|
2014-02-05 17:31:33 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
fn process_enum(&mut self,
|
|
|
|
item: &ast::Item,
|
|
|
|
enum_definition: &ast::EnumDef,
|
|
|
|
ty_params: &ast::Generics) {
|
2014-06-21 03:39:03 -07:00
|
|
|
let qualname = self.analysis.ty_cx.map.path_to_string(item.id);
|
2014-02-05 17:31:33 +13:00
|
|
|
match self.span.sub_span_after_keyword(item.span, keywords::Enum) {
|
|
|
|
Some(sub_span) => self.fmt.enum_str(item.span,
|
|
|
|
Some(sub_span),
|
|
|
|
item.id,
|
|
|
|
qualname.as_slice(),
|
2014-09-12 13:10:30 +03:00
|
|
|
self.cur_scope),
|
2014-02-05 17:31:33 +13:00
|
|
|
None => self.sess.span_bug(item.span,
|
|
|
|
format!("Could not find subspan for enum {}",
|
|
|
|
qualname).as_slice()),
|
|
|
|
}
|
|
|
|
for variant in enum_definition.variants.iter() {
|
|
|
|
let name = get_ident(variant.node.name);
|
|
|
|
let name = name.get();
|
2014-10-14 23:05:01 -07:00
|
|
|
let mut qualname = qualname.clone();
|
|
|
|
qualname.push_str("::");
|
|
|
|
qualname.push_str(name);
|
2014-02-05 17:31:33 +13:00
|
|
|
let val = self.span.snippet(variant.span);
|
|
|
|
match variant.node.kind {
|
|
|
|
ast::TupleVariantKind(ref args) => {
|
|
|
|
// first ident in span is the variant's name
|
|
|
|
self.fmt.tuple_variant_str(variant.span,
|
|
|
|
self.span.span_for_first_ident(variant.span),
|
|
|
|
variant.node.id,
|
|
|
|
name,
|
|
|
|
qualname.as_slice(),
|
|
|
|
val.as_slice(),
|
|
|
|
item.id);
|
|
|
|
for arg in args.iter() {
|
2014-09-12 13:10:30 +03:00
|
|
|
self.visit_ty(&*arg.ty);
|
2014-02-05 17:31:33 +13:00
|
|
|
}
|
|
|
|
}
|
|
|
|
ast::StructVariantKind(ref struct_def) => {
|
|
|
|
let ctor_id = match struct_def.ctor_id {
|
|
|
|
Some(node_id) => node_id,
|
|
|
|
None => -1,
|
|
|
|
};
|
|
|
|
self.fmt.struct_variant_str(
|
|
|
|
variant.span,
|
|
|
|
self.span.span_for_first_ident(variant.span),
|
|
|
|
variant.node.id,
|
|
|
|
ctor_id,
|
|
|
|
qualname.as_slice(),
|
|
|
|
val.as_slice(),
|
|
|
|
item.id);
|
|
|
|
|
|
|
|
for field in struct_def.fields.iter() {
|
|
|
|
self.process_struct_field_def(field, qualname.as_slice(), variant.node.id);
|
2014-09-12 13:10:30 +03:00
|
|
|
self.visit_ty(&*field.node.ty);
|
2014-02-05 17:31:33 +13:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-12 13:10:30 +03:00
|
|
|
self.process_generic_params(ty_params, item.span, qualname.as_slice(), item.id);
|
2014-02-05 17:31:33 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
fn process_impl(&mut self,
|
|
|
|
item: &ast::Item,
|
|
|
|
type_parameters: &ast::Generics,
|
|
|
|
trait_ref: &Option<ast::TraitRef>,
|
2014-09-07 20:09:06 +03:00
|
|
|
typ: &ast::Ty,
|
2014-08-04 13:56:56 -07:00
|
|
|
impl_items: &Vec<ast::ImplItem>) {
|
2014-02-05 17:31:33 +13:00
|
|
|
match typ.node {
|
|
|
|
ast::TyPath(ref path, _, id) => {
|
|
|
|
match self.lookup_type_ref(id) {
|
|
|
|
Some(id) => {
|
|
|
|
let sub_span = self.span.sub_span_for_type_name(path.span);
|
|
|
|
self.fmt.ref_str(recorder::TypeRef,
|
|
|
|
path.span,
|
|
|
|
sub_span,
|
|
|
|
id,
|
2014-09-12 13:10:30 +03:00
|
|
|
self.cur_scope);
|
2014-02-05 17:31:33 +13:00
|
|
|
self.fmt.impl_str(path.span,
|
|
|
|
sub_span,
|
|
|
|
item.id,
|
|
|
|
id,
|
2014-09-12 13:10:30 +03:00
|
|
|
self.cur_scope);
|
2014-02-05 17:31:33 +13:00
|
|
|
},
|
|
|
|
None => ()
|
|
|
|
}
|
|
|
|
},
|
2014-09-12 13:10:30 +03:00
|
|
|
_ => self.visit_ty(&*typ),
|
2014-02-05 17:31:33 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
match *trait_ref {
|
2014-09-12 13:10:30 +03:00
|
|
|
Some(ref trait_ref) => self.process_trait_ref(trait_ref, Some(item.id)),
|
2014-02-05 17:31:33 +13:00
|
|
|
None => (),
|
|
|
|
}
|
|
|
|
|
2014-09-12 13:10:30 +03:00
|
|
|
self.process_generic_params(type_parameters, item.span, "", item.id);
|
2014-08-04 13:56:56 -07:00
|
|
|
for impl_item in impl_items.iter() {
|
|
|
|
match *impl_item {
|
2014-09-07 20:09:06 +03:00
|
|
|
ast::MethodImplItem(ref method) => {
|
|
|
|
visit::walk_method_helper(self, &**method)
|
2014-08-04 13:56:56 -07:00
|
|
|
}
|
2014-08-05 19:44:21 -07:00
|
|
|
ast::TypeImplItem(ref typedef) => {
|
|
|
|
visit::walk_ty(self, &*typedef.typ)
|
|
|
|
}
|
2014-08-04 13:56:56 -07:00
|
|
|
}
|
2014-02-05 17:31:33 +13:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn process_trait(&mut self,
|
|
|
|
item: &ast::Item,
|
|
|
|
generics: &ast::Generics,
|
2014-08-27 21:46:52 -04:00
|
|
|
trait_refs: &OwnedSlice<ast::TyParamBound>,
|
2014-08-04 13:56:56 -07:00
|
|
|
methods: &Vec<ast::TraitItem>) {
|
2014-06-21 03:39:03 -07:00
|
|
|
let qualname = self.analysis.ty_cx.map.path_to_string(item.id);
|
2014-02-05 17:31:33 +13:00
|
|
|
|
|
|
|
let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Trait);
|
|
|
|
self.fmt.trait_str(item.span,
|
|
|
|
sub_span,
|
|
|
|
item.id,
|
|
|
|
qualname.as_slice(),
|
2014-09-12 13:10:30 +03:00
|
|
|
self.cur_scope);
|
2014-02-05 17:31:33 +13:00
|
|
|
|
|
|
|
// super-traits
|
2014-08-27 21:46:52 -04:00
|
|
|
for super_bound in trait_refs.iter() {
|
|
|
|
let trait_ref = match *super_bound {
|
|
|
|
ast::TraitTyParamBound(ref trait_ref) => {
|
|
|
|
trait_ref
|
|
|
|
}
|
2014-11-04 16:25:15 -05:00
|
|
|
ast::RegionTyParamBound(..) => {
|
2014-08-27 21:46:52 -04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-11-07 06:53:45 -05:00
|
|
|
let trait_ref = &trait_ref.trait_ref;
|
2014-02-05 17:31:33 +13:00
|
|
|
match self.lookup_type_ref(trait_ref.ref_id) {
|
|
|
|
Some(id) => {
|
|
|
|
let sub_span = self.span.sub_span_for_type_name(trait_ref.path.span);
|
|
|
|
self.fmt.ref_str(recorder::TypeRef,
|
|
|
|
trait_ref.path.span,
|
|
|
|
sub_span,
|
|
|
|
id,
|
2014-09-12 13:10:30 +03:00
|
|
|
self.cur_scope);
|
2014-02-05 17:31:33 +13:00
|
|
|
self.fmt.inherit_str(trait_ref.path.span,
|
|
|
|
sub_span,
|
|
|
|
id,
|
|
|
|
item.id);
|
|
|
|
},
|
|
|
|
None => ()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// walk generics and methods
|
2014-09-12 13:10:30 +03:00
|
|
|
self.process_generic_params(generics, item.span, qualname.as_slice(), item.id);
|
2014-02-05 17:31:33 +13:00
|
|
|
for method in methods.iter() {
|
2014-09-12 13:10:30 +03:00
|
|
|
self.visit_trait_item(method)
|
2014-02-05 17:31:33 +13:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn process_mod(&mut self,
|
|
|
|
item: &ast::Item, // The module in question, represented as an item.
|
|
|
|
m: &ast::Mod) {
|
2014-06-21 03:39:03 -07:00
|
|
|
let qualname = self.analysis.ty_cx.map.path_to_string(item.id);
|
2014-02-05 17:31:33 +13:00
|
|
|
|
|
|
|
let cm = self.sess.codemap();
|
|
|
|
let filename = cm.span_to_filename(m.inner);
|
|
|
|
|
|
|
|
let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Mod);
|
|
|
|
self.fmt.mod_str(item.span,
|
|
|
|
sub_span,
|
|
|
|
item.id,
|
|
|
|
qualname.as_slice(),
|
2014-09-12 13:10:30 +03:00
|
|
|
self.cur_scope,
|
2014-02-05 17:31:33 +13:00
|
|
|
filename.as_slice());
|
|
|
|
|
2014-09-12 13:10:30 +03:00
|
|
|
self.nest(item.id, |v| visit::walk_mod(v, m));
|
2014-02-05 17:31:33 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
fn process_path(&mut self,
|
|
|
|
ex: &ast::Expr,
|
|
|
|
path: &ast::Path) {
|
|
|
|
if generated_code(path.span) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
let def_map = self.analysis.ty_cx.def_map.borrow();
|
|
|
|
if !def_map.contains_key(&ex.id) {
|
|
|
|
self.sess.span_bug(ex.span,
|
|
|
|
format!("def_map has no key for {} in visit_expr",
|
|
|
|
ex.id).as_slice());
|
|
|
|
}
|
2014-10-14 23:05:01 -07:00
|
|
|
let def = &(*def_map)[ex.id];
|
2014-02-05 17:31:33 +13:00
|
|
|
let sub_span = self.span.span_for_last_ident(ex.span);
|
|
|
|
match *def {
|
2014-09-17 18:17:09 +03:00
|
|
|
def::DefUpvar(..) |
|
|
|
|
def::DefLocal(..) |
|
|
|
|
def::DefStatic(..) |
|
rustc: Add `const` globals to the language
This change is an implementation of [RFC 69][rfc] which adds a third kind of
global to the language, `const`. This global is most similar to what the old
`static` was, and if you're unsure about what to use then you should use a
`const`.
The semantics of these three kinds of globals are:
* A `const` does not represent a memory location, but only a value. Constants
are translated as rvalues, which means that their values are directly inlined
at usage location (similar to a #define in C/C++). Constant values are, well,
constant, and can not be modified. Any "modification" is actually a
modification to a local value on the stack rather than the actual constant
itself.
Almost all values are allowed inside constants, whether they have interior
mutability or not. There are a few minor restrictions listed in the RFC, but
they should in general not come up too often.
* A `static` now always represents a memory location (unconditionally). Any
references to the same `static` are actually a reference to the same memory
location. Only values whose types ascribe to `Sync` are allowed in a `static`.
This restriction is in place because many threads may access a `static`
concurrently. Lifting this restriction (and allowing unsafe access) is a
future extension not implemented at this time.
* A `static mut` continues to always represent a memory location. All references
to a `static mut` continue to be `unsafe`.
This is a large breaking change, and many programs will need to be updated
accordingly. A summary of the breaking changes is:
* Statics may no longer be used in patterns. Statics now always represent a
memory location, which can sometimes be modified. To fix code, repurpose the
matched-on-`static` to a `const`.
static FOO: uint = 4;
match n {
FOO => { /* ... */ }
_ => { /* ... */ }
}
change this code to:
const FOO: uint = 4;
match n {
FOO => { /* ... */ }
_ => { /* ... */ }
}
* Statics may no longer refer to other statics by value. Due to statics being
able to change at runtime, allowing them to reference one another could
possibly lead to confusing semantics. If you are in this situation, use a
constant initializer instead. Note, however, that statics may reference other
statics by address, however.
* Statics may no longer be used in constant expressions, such as array lengths.
This is due to the same restrictions as listed above. Use a `const` instead.
[breaking-change]
[rfc]: https://github.com/rust-lang/rfcs/pull/246
2014-10-06 08:17:01 -07:00
|
|
|
def::DefConst(..) |
|
2014-09-17 18:17:09 +03:00
|
|
|
def::DefVariant(..) => self.fmt.ref_str(recorder::VarRef,
|
|
|
|
ex.span,
|
|
|
|
sub_span,
|
|
|
|
def.def_id(),
|
|
|
|
self.cur_scope),
|
2014-02-05 17:31:33 +13:00
|
|
|
def::DefStruct(def_id) => self.fmt.ref_str(recorder::StructRef,
|
|
|
|
ex.span,
|
|
|
|
sub_span,
|
|
|
|
def_id,
|
2014-09-12 13:10:30 +03:00
|
|
|
self.cur_scope),
|
2014-10-16 17:44:24 +13:00
|
|
|
def::DefStaticMethod(declid, provenence) => {
|
2014-02-05 17:31:33 +13:00
|
|
|
let sub_span = self.span.sub_span_for_meth_name(ex.span);
|
|
|
|
let defid = if declid.krate == ast::LOCAL_CRATE {
|
2014-08-04 13:56:56 -07:00
|
|
|
let ti = ty::impl_or_trait_item(&self.analysis.ty_cx,
|
|
|
|
declid);
|
2014-02-05 17:31:33 +13:00
|
|
|
match provenence {
|
2014-08-04 13:56:56 -07:00
|
|
|
def::FromTrait(def_id) => {
|
|
|
|
Some(ty::trait_items(&self.analysis.ty_cx,
|
|
|
|
def_id)
|
|
|
|
.iter()
|
|
|
|
.find(|mr| {
|
2014-09-30 19:11:34 -05:00
|
|
|
mr.name() == ti.name()
|
2014-08-04 13:56:56 -07:00
|
|
|
})
|
|
|
|
.unwrap()
|
|
|
|
.def_id())
|
|
|
|
}
|
2014-02-05 17:31:33 +13:00
|
|
|
def::FromImpl(def_id) => {
|
2014-08-04 13:56:56 -07:00
|
|
|
let impl_items = self.analysis
|
|
|
|
.ty_cx
|
|
|
|
.impl_items
|
|
|
|
.borrow();
|
2014-10-14 23:05:01 -07:00
|
|
|
Some((*impl_items)[def_id]
|
2014-08-04 13:56:56 -07:00
|
|
|
.iter()
|
|
|
|
.find(|mr| {
|
2014-09-30 19:11:34 -05:00
|
|
|
ty::impl_or_trait_item(
|
|
|
|
&self.analysis.ty_cx,
|
|
|
|
mr.def_id()
|
|
|
|
).name() == ti.name()
|
2014-08-05 19:44:21 -07:00
|
|
|
})
|
|
|
|
.unwrap()
|
|
|
|
.def_id())
|
2014-02-05 17:31:33 +13:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
self.fmt.meth_call_str(ex.span,
|
|
|
|
sub_span,
|
|
|
|
defid,
|
|
|
|
Some(declid),
|
2014-09-12 13:10:30 +03:00
|
|
|
self.cur_scope);
|
2014-02-05 17:31:33 +13:00
|
|
|
},
|
2014-10-16 17:44:24 +13:00
|
|
|
def::DefFn(def_id, _) => self.fmt.fn_call_str(ex.span,
|
2014-09-29 18:27:07 +02:00
|
|
|
sub_span,
|
|
|
|
def_id,
|
|
|
|
self.cur_scope),
|
2014-02-05 17:31:33 +13:00
|
|
|
_ => self.sess.span_bug(ex.span,
|
|
|
|
format!("Unexpected def kind while looking up path in '{}'",
|
|
|
|
self.span.snippet(ex.span)).as_slice()),
|
|
|
|
}
|
|
|
|
// modules or types in the path prefix
|
|
|
|
match *def {
|
2014-10-16 17:44:24 +13:00
|
|
|
def::DefStaticMethod(..) => {
|
2014-09-12 13:10:30 +03:00
|
|
|
self.write_sub_path_trait_truncated(path);
|
2014-02-05 17:31:33 +13:00
|
|
|
},
|
2014-09-17 18:17:09 +03:00
|
|
|
def::DefLocal(_) |
|
2014-02-05 17:31:33 +13:00
|
|
|
def::DefStatic(_,_) |
|
rustc: Add `const` globals to the language
This change is an implementation of [RFC 69][rfc] which adds a third kind of
global to the language, `const`. This global is most similar to what the old
`static` was, and if you're unsure about what to use then you should use a
`const`.
The semantics of these three kinds of globals are:
* A `const` does not represent a memory location, but only a value. Constants
are translated as rvalues, which means that their values are directly inlined
at usage location (similar to a #define in C/C++). Constant values are, well,
constant, and can not be modified. Any "modification" is actually a
modification to a local value on the stack rather than the actual constant
itself.
Almost all values are allowed inside constants, whether they have interior
mutability or not. There are a few minor restrictions listed in the RFC, but
they should in general not come up too often.
* A `static` now always represents a memory location (unconditionally). Any
references to the same `static` are actually a reference to the same memory
location. Only values whose types ascribe to `Sync` are allowed in a `static`.
This restriction is in place because many threads may access a `static`
concurrently. Lifting this restriction (and allowing unsafe access) is a
future extension not implemented at this time.
* A `static mut` continues to always represent a memory location. All references
to a `static mut` continue to be `unsafe`.
This is a large breaking change, and many programs will need to be updated
accordingly. A summary of the breaking changes is:
* Statics may no longer be used in patterns. Statics now always represent a
memory location, which can sometimes be modified. To fix code, repurpose the
matched-on-`static` to a `const`.
static FOO: uint = 4;
match n {
FOO => { /* ... */ }
_ => { /* ... */ }
}
change this code to:
const FOO: uint = 4;
match n {
FOO => { /* ... */ }
_ => { /* ... */ }
}
* Statics may no longer refer to other statics by value. Due to statics being
able to change at runtime, allowing them to reference one another could
possibly lead to confusing semantics. If you are in this situation, use a
constant initializer instead. Note, however, that statics may reference other
statics by address, however.
* Statics may no longer be used in constant expressions, such as array lengths.
This is due to the same restrictions as listed above. Use a `const` instead.
[breaking-change]
[rfc]: https://github.com/rust-lang/rfcs/pull/246
2014-10-06 08:17:01 -07:00
|
|
|
def::DefConst(..) |
|
2014-02-05 17:31:33 +13:00
|
|
|
def::DefStruct(_) |
|
2014-09-29 18:27:07 +02:00
|
|
|
def::DefFn(..) => self.write_sub_paths_truncated(path),
|
2014-02-05 17:31:33 +13:00
|
|
|
_ => {},
|
|
|
|
}
|
|
|
|
|
2014-09-12 13:10:30 +03:00
|
|
|
visit::walk_path(self, path);
|
2014-02-05 17:31:33 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
fn process_struct_lit(&mut self,
|
|
|
|
ex: &ast::Expr,
|
|
|
|
path: &ast::Path,
|
|
|
|
fields: &Vec<ast::Field>,
|
2014-09-07 20:09:06 +03:00
|
|
|
base: &Option<P<ast::Expr>>) {
|
2014-02-05 17:31:33 +13:00
|
|
|
if generated_code(path.span) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut struct_def: Option<DefId> = None;
|
|
|
|
match self.lookup_type_ref(ex.id) {
|
|
|
|
Some(id) => {
|
|
|
|
struct_def = Some(id);
|
|
|
|
let sub_span = self.span.span_for_last_ident(path.span);
|
|
|
|
self.fmt.ref_str(recorder::StructRef,
|
|
|
|
path.span,
|
|
|
|
sub_span,
|
|
|
|
id,
|
2014-09-12 13:10:30 +03:00
|
|
|
self.cur_scope);
|
2014-02-05 17:31:33 +13:00
|
|
|
},
|
|
|
|
None => ()
|
|
|
|
}
|
|
|
|
|
2014-09-12 13:10:30 +03:00
|
|
|
self.write_sub_paths_truncated(path);
|
2014-02-05 17:31:33 +13:00
|
|
|
|
|
|
|
for field in fields.iter() {
|
|
|
|
match struct_def {
|
|
|
|
Some(struct_def) => {
|
|
|
|
let fields = ty::lookup_struct_fields(&self.analysis.ty_cx, struct_def);
|
|
|
|
for f in fields.iter() {
|
|
|
|
if generated_code(field.ident.span) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if f.name == field.ident.node.name {
|
|
|
|
// We don't really need a sub-span here, but no harm done
|
|
|
|
let sub_span = self.span.span_for_last_ident(field.ident.span);
|
|
|
|
self.fmt.ref_str(recorder::VarRef,
|
|
|
|
field.ident.span,
|
|
|
|
sub_span,
|
|
|
|
f.id,
|
2014-09-12 13:10:30 +03:00
|
|
|
self.cur_scope);
|
2014-02-05 17:31:33 +13:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None => {}
|
|
|
|
}
|
|
|
|
|
2014-09-12 13:10:30 +03:00
|
|
|
self.visit_expr(&*field.expr)
|
2014-02-05 17:31:33 +13:00
|
|
|
}
|
2014-09-12 13:10:30 +03:00
|
|
|
visit::walk_expr_opt(self, base)
|
2014-02-05 17:31:33 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
fn process_method_call(&mut self,
|
|
|
|
ex: &ast::Expr,
|
2014-09-07 20:09:06 +03:00
|
|
|
args: &Vec<P<ast::Expr>>) {
|
2014-02-05 17:31:33 +13:00
|
|
|
let method_map = self.analysis.ty_cx.method_map.borrow();
|
2014-10-14 23:05:01 -07:00
|
|
|
let method_callee = &(*method_map)[typeck::MethodCall::expr(ex.id)];
|
2014-02-05 17:31:33 +13:00
|
|
|
let (def_id, decl_id) = match method_callee.origin {
|
2014-05-28 22:26:56 -07:00
|
|
|
typeck::MethodStatic(def_id) |
|
|
|
|
typeck::MethodStaticUnboxedClosure(def_id) => {
|
2014-02-05 17:31:33 +13:00
|
|
|
// method invoked on an object with a concrete type (not a static method)
|
2014-08-04 13:56:56 -07:00
|
|
|
let decl_id =
|
|
|
|
match ty::trait_item_of_item(&self.analysis.ty_cx,
|
|
|
|
def_id) {
|
|
|
|
None => None,
|
2014-08-05 19:44:21 -07:00
|
|
|
Some(decl_id) => Some(decl_id.def_id()),
|
2014-08-04 13:56:56 -07:00
|
|
|
};
|
2014-02-05 17:31:33 +13:00
|
|
|
|
2014-08-04 13:56:56 -07:00
|
|
|
// This incantation is required if the method referenced is a
|
|
|
|
// trait's default implementation.
|
|
|
|
let def_id = match ty::impl_or_trait_item(&self.analysis
|
|
|
|
.ty_cx,
|
|
|
|
def_id) {
|
|
|
|
ty::MethodTraitItem(method) => {
|
|
|
|
method.provided_source.unwrap_or(def_id)
|
|
|
|
}
|
2014-08-05 19:44:21 -07:00
|
|
|
ty::TypeTraitItem(_) => def_id,
|
2014-08-04 13:56:56 -07:00
|
|
|
};
|
2014-02-05 17:31:33 +13:00
|
|
|
(Some(def_id), decl_id)
|
|
|
|
}
|
2014-09-11 17:07:49 +12:00
|
|
|
typeck::MethodTypeParam(ref mp) => {
|
2014-02-05 17:31:33 +13:00
|
|
|
// method invoked on a type parameter
|
2014-08-04 13:56:56 -07:00
|
|
|
let trait_item = ty::trait_item(&self.analysis.ty_cx,
|
2014-09-12 11:42:58 -04:00
|
|
|
mp.trait_ref.def_id,
|
2014-08-04 13:56:56 -07:00
|
|
|
mp.method_num);
|
2014-08-05 19:44:21 -07:00
|
|
|
(None, Some(trait_item.def_id()))
|
|
|
|
}
|
2014-09-11 17:07:49 +12:00
|
|
|
typeck::MethodTraitObject(ref mo) => {
|
2014-02-05 17:31:33 +13:00
|
|
|
// method invoked on a trait instance
|
2014-08-04 13:56:56 -07:00
|
|
|
let trait_item = ty::trait_item(&self.analysis.ty_cx,
|
2014-09-12 11:42:58 -04:00
|
|
|
mo.trait_ref.def_id,
|
2014-08-04 13:56:56 -07:00
|
|
|
mo.method_num);
|
2014-08-05 19:44:21 -07:00
|
|
|
(None, Some(trait_item.def_id()))
|
|
|
|
}
|
2014-02-05 17:31:33 +13:00
|
|
|
};
|
|
|
|
let sub_span = self.span.sub_span_for_meth_name(ex.span);
|
|
|
|
self.fmt.meth_call_str(ex.span,
|
|
|
|
sub_span,
|
|
|
|
def_id,
|
|
|
|
decl_id,
|
2014-09-12 13:10:30 +03:00
|
|
|
self.cur_scope);
|
2014-02-05 17:31:33 +13:00
|
|
|
|
|
|
|
// walk receiver and args
|
2014-09-12 13:10:30 +03:00
|
|
|
visit::walk_exprs(self, args.as_slice());
|
2014-02-05 17:31:33 +13:00
|
|
|
}
|
|
|
|
|
2014-09-12 13:10:30 +03:00
|
|
|
fn process_pat(&mut self, p:&ast::Pat) {
|
2014-02-05 17:31:33 +13:00
|
|
|
if generated_code(p.span) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
match p.node {
|
|
|
|
ast::PatStruct(ref path, ref fields, _) => {
|
|
|
|
self.collected_paths.push((p.id, path.clone(), false, recorder::StructRef));
|
2014-09-12 13:10:30 +03:00
|
|
|
visit::walk_path(self, path);
|
2014-02-05 17:31:33 +13:00
|
|
|
let struct_def = match self.lookup_type_ref(p.id) {
|
|
|
|
Some(sd) => sd,
|
|
|
|
None => {
|
|
|
|
self.sess.span_bug(p.span,
|
|
|
|
format!("Could not find struct_def for `{}`",
|
|
|
|
self.span.snippet(p.span)).as_slice());
|
|
|
|
}
|
|
|
|
};
|
2014-10-06 13:36:53 +13:00
|
|
|
for &Spanned { node: ref field, span } in fields.iter() {
|
2014-09-12 13:10:30 +03:00
|
|
|
self.visit_pat(&*field.pat);
|
2014-02-05 17:31:33 +13:00
|
|
|
let fields = ty::lookup_struct_fields(&self.analysis.ty_cx, struct_def);
|
|
|
|
for f in fields.iter() {
|
|
|
|
if f.name == field.ident.name {
|
|
|
|
self.fmt.ref_str(recorder::VarRef,
|
|
|
|
p.span,
|
2014-10-06 13:36:53 +13:00
|
|
|
Some(span),
|
2014-02-05 17:31:33 +13:00
|
|
|
f.id,
|
2014-09-12 13:10:30 +03:00
|
|
|
self.cur_scope);
|
2014-02-05 17:31:33 +13:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ast::PatEnum(ref path, _) => {
|
|
|
|
self.collected_paths.push((p.id, path.clone(), false, recorder::VarRef));
|
2014-09-12 13:10:30 +03:00
|
|
|
visit::walk_pat(self, p);
|
2014-02-05 17:31:33 +13:00
|
|
|
}
|
2014-06-30 18:02:14 -07:00
|
|
|
ast::PatIdent(bm, ref path1, ref optional_subpattern) => {
|
2014-02-05 17:31:33 +13:00
|
|
|
let immut = match bm {
|
|
|
|
// Even if the ref is mut, you can't change the ref, only
|
|
|
|
// the data pointed at, so showing the initialising expression
|
|
|
|
// is still worthwhile.
|
|
|
|
ast::BindByRef(_) => true,
|
|
|
|
ast::BindByValue(mt) => {
|
|
|
|
match mt {
|
|
|
|
ast::MutMutable => false,
|
|
|
|
ast::MutImmutable => true,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
// collect path for either visit_local or visit_arm
|
2014-06-30 18:02:14 -07:00
|
|
|
let path = ast_util::ident_to_path(path1.span,path1.node);
|
|
|
|
self.collected_paths.push((p.id, path, immut, recorder::VarRef));
|
2014-02-05 17:31:33 +13:00
|
|
|
match *optional_subpattern {
|
|
|
|
None => {}
|
2014-09-07 20:09:06 +03:00
|
|
|
Some(ref subpattern) => self.visit_pat(&**subpattern)
|
2014-02-05 17:31:33 +13:00
|
|
|
}
|
|
|
|
}
|
2014-09-12 13:10:30 +03:00
|
|
|
_ => visit::walk_pat(self, p)
|
2014-02-05 17:31:33 +13:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-10 01:54:36 +03:00
|
|
|
impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> {
|
|
|
|
fn visit_item(&mut self, item: &ast::Item) {
|
2014-02-05 17:31:33 +13:00
|
|
|
if generated_code(item.span) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
match item.node {
|
2014-09-07 20:09:06 +03:00
|
|
|
ast::ItemFn(ref decl, _, _, ref ty_params, ref body) =>
|
|
|
|
self.process_fn(item, &**decl, ty_params, &**body),
|
|
|
|
ast::ItemStatic(ref typ, mt, ref expr) =>
|
|
|
|
self.process_static(item, &**typ, mt, &**expr),
|
rustc: Add `const` globals to the language
This change is an implementation of [RFC 69][rfc] which adds a third kind of
global to the language, `const`. This global is most similar to what the old
`static` was, and if you're unsure about what to use then you should use a
`const`.
The semantics of these three kinds of globals are:
* A `const` does not represent a memory location, but only a value. Constants
are translated as rvalues, which means that their values are directly inlined
at usage location (similar to a #define in C/C++). Constant values are, well,
constant, and can not be modified. Any "modification" is actually a
modification to a local value on the stack rather than the actual constant
itself.
Almost all values are allowed inside constants, whether they have interior
mutability or not. There are a few minor restrictions listed in the RFC, but
they should in general not come up too often.
* A `static` now always represents a memory location (unconditionally). Any
references to the same `static` are actually a reference to the same memory
location. Only values whose types ascribe to `Sync` are allowed in a `static`.
This restriction is in place because many threads may access a `static`
concurrently. Lifting this restriction (and allowing unsafe access) is a
future extension not implemented at this time.
* A `static mut` continues to always represent a memory location. All references
to a `static mut` continue to be `unsafe`.
This is a large breaking change, and many programs will need to be updated
accordingly. A summary of the breaking changes is:
* Statics may no longer be used in patterns. Statics now always represent a
memory location, which can sometimes be modified. To fix code, repurpose the
matched-on-`static` to a `const`.
static FOO: uint = 4;
match n {
FOO => { /* ... */ }
_ => { /* ... */ }
}
change this code to:
const FOO: uint = 4;
match n {
FOO => { /* ... */ }
_ => { /* ... */ }
}
* Statics may no longer refer to other statics by value. Due to statics being
able to change at runtime, allowing them to reference one another could
possibly lead to confusing semantics. If you are in this situation, use a
constant initializer instead. Note, however, that statics may reference other
statics by address, however.
* Statics may no longer be used in constant expressions, such as array lengths.
This is due to the same restrictions as listed above. Use a `const` instead.
[breaking-change]
[rfc]: https://github.com/rust-lang/rfcs/pull/246
2014-10-06 08:17:01 -07:00
|
|
|
ast::ItemConst(ref typ, ref expr) =>
|
|
|
|
self.process_const(item, &**typ, &**expr),
|
2014-09-07 20:09:06 +03:00
|
|
|
ast::ItemStruct(ref def, ref ty_params) => self.process_struct(item, &**def, ty_params),
|
2014-09-12 13:10:30 +03:00
|
|
|
ast::ItemEnum(ref def, ref ty_params) => self.process_enum(item, def, ty_params),
|
2014-08-04 13:56:56 -07:00
|
|
|
ast::ItemImpl(ref ty_params,
|
|
|
|
ref trait_ref,
|
2014-09-07 20:09:06 +03:00
|
|
|
ref typ,
|
2014-08-04 13:56:56 -07:00
|
|
|
ref impl_items) => {
|
|
|
|
self.process_impl(item,
|
|
|
|
ty_params,
|
|
|
|
trait_ref,
|
2014-09-07 20:09:06 +03:00
|
|
|
&**typ,
|
2014-08-04 13:56:56 -07:00
|
|
|
impl_items)
|
|
|
|
}
|
2014-02-05 17:31:33 +13:00
|
|
|
ast::ItemTrait(ref generics, _, ref trait_refs, ref methods) =>
|
2014-09-12 13:10:30 +03:00
|
|
|
self.process_trait(item, generics, trait_refs, methods),
|
|
|
|
ast::ItemMod(ref m) => self.process_mod(item, m),
|
2014-09-07 20:09:06 +03:00
|
|
|
ast::ItemTy(ref ty, ref ty_params) => {
|
2014-06-21 03:39:03 -07:00
|
|
|
let qualname = self.analysis.ty_cx.map.path_to_string(item.id);
|
2014-09-07 20:09:06 +03:00
|
|
|
let value = ty_to_string(&**ty);
|
2014-02-05 17:31:33 +13:00
|
|
|
let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Type);
|
|
|
|
self.fmt.typedef_str(item.span,
|
|
|
|
sub_span,
|
|
|
|
item.id,
|
|
|
|
qualname.as_slice(),
|
|
|
|
value.as_slice());
|
|
|
|
|
2014-09-07 20:09:06 +03:00
|
|
|
self.visit_ty(&**ty);
|
2014-09-12 13:10:30 +03:00
|
|
|
self.process_generic_params(ty_params, item.span, qualname.as_slice(), item.id);
|
2014-02-05 17:31:33 +13:00
|
|
|
},
|
|
|
|
ast::ItemMac(_) => (),
|
2014-09-12 13:10:30 +03:00
|
|
|
_ => visit::walk_item(self, item),
|
2014-02-05 17:31:33 +13:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-12 13:10:30 +03:00
|
|
|
fn visit_generics(&mut self, generics: &ast::Generics) {
|
2014-02-05 17:31:33 +13:00
|
|
|
for param in generics.ty_params.iter() {
|
|
|
|
for bound in param.bounds.iter() {
|
|
|
|
match *bound {
|
|
|
|
ast::TraitTyParamBound(ref trait_ref) => {
|
2014-11-07 06:53:45 -05:00
|
|
|
self.process_trait_ref(&trait_ref.trait_ref, None);
|
2014-02-05 17:31:33 +13:00
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
match param.default {
|
2014-09-07 20:09:06 +03:00
|
|
|
Some(ref ty) => self.visit_ty(&**ty),
|
|
|
|
None => {}
|
2014-02-05 17:31:33 +13:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// We don't actually index functions here, that is done in visit_item/ItemFn.
|
|
|
|
// Here we just visit methods.
|
|
|
|
fn visit_fn(&mut self,
|
2014-09-10 01:54:36 +03:00
|
|
|
fk: visit::FnKind<'v>,
|
|
|
|
fd: &'v ast::FnDecl,
|
|
|
|
b: &'v ast::Block,
|
2014-02-05 17:31:33 +13:00
|
|
|
s: Span,
|
2014-09-12 13:10:30 +03:00
|
|
|
_: NodeId) {
|
2014-02-05 17:31:33 +13:00
|
|
|
if generated_code(s) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-09-10 01:54:36 +03:00
|
|
|
match fk {
|
2014-09-12 13:10:30 +03:00
|
|
|
visit::FkMethod(_, _, method) => self.process_method(method),
|
|
|
|
_ => visit::walk_fn(self, fk, fd, b, s),
|
2014-02-05 17:31:33 +13:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-12 13:10:30 +03:00
|
|
|
fn visit_trait_item(&mut self, tm: &ast::TraitItem) {
|
2014-02-05 17:31:33 +13:00
|
|
|
match *tm {
|
2014-08-04 13:56:56 -07:00
|
|
|
ast::RequiredMethod(ref method_type) => {
|
2014-02-05 17:31:33 +13:00
|
|
|
if generated_code(method_type.span) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-08-04 13:56:56 -07:00
|
|
|
let mut scope_id;
|
|
|
|
let mut qualname = match ty::trait_of_item(&self.analysis.ty_cx,
|
|
|
|
ast_util::local_def(method_type.id)) {
|
2014-02-05 17:31:33 +13:00
|
|
|
Some(def_id) => {
|
|
|
|
scope_id = def_id.node;
|
2014-10-14 23:05:01 -07:00
|
|
|
let mut s = ty::item_path_str(&self.analysis.ty_cx, def_id);
|
|
|
|
s.push_str("::");
|
|
|
|
s
|
2014-02-05 17:31:33 +13:00
|
|
|
},
|
|
|
|
None => {
|
|
|
|
self.sess.span_bug(method_type.span,
|
|
|
|
format!("Could not find trait for method {}",
|
|
|
|
method_type.id).as_slice());
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
qualname.push_str(get_ident(method_type.ident).get());
|
|
|
|
let qualname = qualname.as_slice();
|
|
|
|
|
|
|
|
let sub_span = self.span.sub_span_after_keyword(method_type.span, keywords::Fn);
|
|
|
|
self.fmt.method_decl_str(method_type.span,
|
|
|
|
sub_span,
|
|
|
|
method_type.id,
|
|
|
|
qualname,
|
|
|
|
scope_id);
|
|
|
|
|
|
|
|
// walk arg and return types
|
|
|
|
for arg in method_type.decl.inputs.iter() {
|
2014-09-12 13:10:30 +03:00
|
|
|
self.visit_ty(&*arg.ty);
|
2014-02-05 17:31:33 +13:00
|
|
|
}
|
2014-11-09 16:14:15 +01:00
|
|
|
|
|
|
|
if let ast::Return(ref ret_ty) = method_type.decl.output {
|
|
|
|
self.visit_ty(&**ret_ty);
|
|
|
|
}
|
2014-02-05 17:31:33 +13:00
|
|
|
|
|
|
|
self.process_generic_params(&method_type.generics,
|
|
|
|
method_type.span,
|
|
|
|
qualname,
|
2014-09-12 13:10:30 +03:00
|
|
|
method_type.id);
|
2014-02-05 17:31:33 +13:00
|
|
|
}
|
2014-08-05 19:44:21 -07:00
|
|
|
ast::ProvidedMethod(ref method) => self.process_method(&**method),
|
|
|
|
ast::TypeTraitItem(_) => {}
|
2014-02-05 17:31:33 +13:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-10 01:54:36 +03:00
|
|
|
fn visit_view_item(&mut self, i: &ast::ViewItem) {
|
2014-02-05 17:31:33 +13:00
|
|
|
if generated_code(i.span) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
match i.node {
|
|
|
|
ast::ViewItemUse(ref path) => {
|
|
|
|
match path.node {
|
|
|
|
ast::ViewPathSimple(ident, ref path, id) => {
|
|
|
|
let sub_span = self.span.span_for_last_ident(path.span);
|
|
|
|
let mod_id = match self.lookup_type_ref(id) {
|
|
|
|
Some(def_id) => {
|
|
|
|
match self.lookup_def_kind(id, path.span) {
|
|
|
|
Some(kind) => self.fmt.ref_str(kind,
|
|
|
|
path.span,
|
|
|
|
sub_span,
|
|
|
|
def_id,
|
2014-09-12 13:10:30 +03:00
|
|
|
self.cur_scope),
|
2014-02-05 17:31:33 +13:00
|
|
|
None => {},
|
|
|
|
}
|
|
|
|
Some(def_id)
|
|
|
|
},
|
|
|
|
None => None,
|
|
|
|
};
|
|
|
|
|
|
|
|
// 'use' always introduces an alias, if there is not an explicit
|
|
|
|
// one, there is an implicit one.
|
|
|
|
let sub_span =
|
2014-10-27 19:22:52 +11:00
|
|
|
match self.span.sub_span_before_token(path.span, token::Eq) {
|
2014-02-05 17:31:33 +13:00
|
|
|
Some(sub_span) => Some(sub_span),
|
|
|
|
None => sub_span,
|
|
|
|
};
|
|
|
|
|
|
|
|
self.fmt.use_alias_str(path.span,
|
|
|
|
sub_span,
|
|
|
|
id,
|
|
|
|
mod_id,
|
|
|
|
get_ident(ident).get(),
|
2014-09-12 13:10:30 +03:00
|
|
|
self.cur_scope);
|
|
|
|
self.write_sub_paths_truncated(path);
|
2014-02-05 17:31:33 +13:00
|
|
|
}
|
|
|
|
ast::ViewPathGlob(ref path, _) => {
|
2014-09-12 13:10:30 +03:00
|
|
|
self.write_sub_paths(path);
|
2014-02-05 17:31:33 +13:00
|
|
|
}
|
|
|
|
ast::ViewPathList(ref path, ref list, _) => {
|
|
|
|
for plid in list.iter() {
|
2014-07-18 00:56:56 +02:00
|
|
|
match plid.node {
|
|
|
|
ast::PathListIdent { id, .. } => {
|
|
|
|
match self.lookup_type_ref(id) {
|
|
|
|
Some(def_id) =>
|
|
|
|
match self.lookup_def_kind(id, plid.span) {
|
|
|
|
Some(kind) => {
|
|
|
|
self.fmt.ref_str(
|
|
|
|
kind, plid.span,
|
|
|
|
Some(plid.span),
|
2014-09-12 13:10:30 +03:00
|
|
|
def_id, self.cur_scope);
|
2014-07-18 00:56:56 +02:00
|
|
|
}
|
|
|
|
None => ()
|
|
|
|
},
|
|
|
|
None => ()
|
|
|
|
}
|
2014-02-05 17:31:33 +13:00
|
|
|
},
|
2014-07-18 00:56:56 +02:00
|
|
|
ast::PathListMod { .. } => ()
|
2014-02-05 17:31:33 +13:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-12 13:10:30 +03:00
|
|
|
self.write_sub_paths(path);
|
2014-02-05 17:31:33 +13:00
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
ast::ViewItemExternCrate(ident, ref s, id) => {
|
2014-07-16 22:37:28 +02:00
|
|
|
let name = get_ident(ident);
|
|
|
|
let name = name.get();
|
2014-02-05 17:31:33 +13:00
|
|
|
let s = match *s {
|
2014-07-16 22:37:28 +02:00
|
|
|
Some((ref s, _)) => s.get().to_string(),
|
|
|
|
None => name.to_string(),
|
2014-02-05 17:31:33 +13:00
|
|
|
};
|
|
|
|
let sub_span = self.span.sub_span_after_keyword(i.span, keywords::Crate);
|
|
|
|
let cnum = match self.sess.cstore.find_extern_mod_stmt_cnum(id) {
|
|
|
|
Some(cnum) => cnum,
|
|
|
|
None => 0,
|
|
|
|
};
|
|
|
|
self.fmt.extern_crate_str(i.span,
|
|
|
|
sub_span,
|
|
|
|
id,
|
|
|
|
cnum,
|
2014-07-16 22:37:28 +02:00
|
|
|
name,
|
2014-02-05 17:31:33 +13:00
|
|
|
s.as_slice(),
|
2014-09-12 13:10:30 +03:00
|
|
|
self.cur_scope);
|
2014-02-05 17:31:33 +13:00
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-12 13:10:30 +03:00
|
|
|
fn visit_ty(&mut self, t: &ast::Ty) {
|
2014-02-05 17:31:33 +13:00
|
|
|
if generated_code(t.span) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
match t.node {
|
|
|
|
ast::TyPath(ref path, _, id) => {
|
|
|
|
match self.lookup_type_ref(id) {
|
|
|
|
Some(id) => {
|
|
|
|
let sub_span = self.span.sub_span_for_type_name(t.span);
|
|
|
|
self.fmt.ref_str(recorder::TypeRef,
|
|
|
|
t.span,
|
|
|
|
sub_span,
|
|
|
|
id,
|
2014-09-12 13:10:30 +03:00
|
|
|
self.cur_scope);
|
2014-02-05 17:31:33 +13:00
|
|
|
},
|
|
|
|
None => ()
|
|
|
|
}
|
|
|
|
|
2014-09-12 13:10:30 +03:00
|
|
|
self.write_sub_paths_truncated(path);
|
2014-02-05 17:31:33 +13:00
|
|
|
|
2014-09-12 13:10:30 +03:00
|
|
|
visit::walk_path(self, path);
|
2014-02-05 17:31:33 +13:00
|
|
|
},
|
2014-09-12 13:10:30 +03:00
|
|
|
_ => visit::walk_ty(self, t),
|
2014-02-05 17:31:33 +13:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-12 13:10:30 +03:00
|
|
|
fn visit_expr(&mut self, ex: &ast::Expr) {
|
2014-02-05 17:31:33 +13:00
|
|
|
if generated_code(ex.span) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
match ex.node {
|
2014-09-07 20:09:06 +03:00
|
|
|
ast::ExprCall(ref _f, ref _args) => {
|
2014-02-05 17:31:33 +13:00
|
|
|
// Don't need to do anything for function calls,
|
|
|
|
// because just walking the callee path does what we want.
|
2014-09-12 13:10:30 +03:00
|
|
|
visit::walk_expr(self, ex);
|
2014-02-05 17:31:33 +13:00
|
|
|
},
|
2014-09-12 13:10:30 +03:00
|
|
|
ast::ExprPath(ref path) => self.process_path(ex, path),
|
2014-09-10 01:54:36 +03:00
|
|
|
ast::ExprStruct(ref path, ref fields, ref base) =>
|
2014-09-12 13:10:30 +03:00
|
|
|
self.process_struct_lit(ex, path, fields, base),
|
|
|
|
ast::ExprMethodCall(_, _, ref args) => self.process_method_call(ex, args),
|
2014-09-07 20:09:06 +03:00
|
|
|
ast::ExprField(ref sub_ex, ident, _) => {
|
2014-02-05 17:31:33 +13:00
|
|
|
if generated_code(sub_ex.span) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2014-09-07 20:09:06 +03:00
|
|
|
self.visit_expr(&**sub_ex);
|
2014-02-05 17:31:33 +13:00
|
|
|
|
2014-09-07 20:09:06 +03:00
|
|
|
let t = ty::expr_ty_adjusted(&self.analysis.ty_cx, &**sub_ex);
|
2014-02-05 17:31:33 +13:00
|
|
|
let t_box = ty::get(t);
|
|
|
|
match t_box.sty {
|
|
|
|
ty::ty_struct(def_id, _) => {
|
|
|
|
let fields = ty::lookup_struct_fields(&self.analysis.ty_cx, def_id);
|
|
|
|
for f in fields.iter() {
|
2014-06-13 22:56:42 +01:00
|
|
|
if f.name == ident.node.name {
|
2014-02-05 17:31:33 +13:00
|
|
|
let sub_span = self.span.span_for_last_ident(ex.span);
|
|
|
|
self.fmt.ref_str(recorder::VarRef,
|
|
|
|
ex.span,
|
|
|
|
sub_span,
|
|
|
|
f.id,
|
2014-09-12 13:10:30 +03:00
|
|
|
self.cur_scope);
|
2014-02-05 17:31:33 +13:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
2014-08-10 15:54:33 +12:00
|
|
|
_ => self.sess.span_bug(ex.span,
|
|
|
|
"Expected struct type, but not ty_struct"),
|
|
|
|
}
|
|
|
|
},
|
2014-09-07 20:09:06 +03:00
|
|
|
ast::ExprTupField(ref sub_ex, idx, _) => {
|
2014-08-10 15:54:33 +12:00
|
|
|
if generated_code(sub_ex.span) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2014-09-07 20:09:06 +03:00
|
|
|
self.visit_expr(&**sub_ex);
|
2014-08-10 15:54:33 +12:00
|
|
|
|
2014-09-07 20:09:06 +03:00
|
|
|
let t = ty::expr_ty_adjusted(&self.analysis.ty_cx, &**sub_ex);
|
2014-08-10 15:54:33 +12:00
|
|
|
let t_box = ty::get(t);
|
|
|
|
match t_box.sty {
|
|
|
|
ty::ty_struct(def_id, _) => {
|
|
|
|
let fields = ty::lookup_struct_fields(&self.analysis.ty_cx, def_id);
|
|
|
|
for (i, f) in fields.iter().enumerate() {
|
|
|
|
if i == idx.node {
|
|
|
|
let sub_span = self.span.span_for_last_ident(ex.span);
|
|
|
|
self.fmt.ref_str(recorder::VarRef,
|
|
|
|
ex.span,
|
|
|
|
sub_span,
|
|
|
|
f.id,
|
2014-09-12 13:10:30 +03:00
|
|
|
self.cur_scope);
|
2014-08-10 15:54:33 +12:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
2014-02-05 17:31:33 +13:00
|
|
|
_ => self.sess.span_bug(ex.span,
|
|
|
|
"Expected struct type, but not ty_struct"),
|
|
|
|
}
|
|
|
|
},
|
2014-09-07 20:09:06 +03:00
|
|
|
ast::ExprFnBlock(_, ref decl, ref body) => {
|
2014-02-05 17:31:33 +13:00
|
|
|
if generated_code(body.span) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2014-10-14 23:05:01 -07:00
|
|
|
let mut id = String::from_str("$");
|
|
|
|
id.push_str(ex.id.to_string().as_slice());
|
2014-09-12 13:10:30 +03:00
|
|
|
self.process_formals(&decl.inputs, id.as_slice());
|
2014-02-05 17:31:33 +13:00
|
|
|
|
|
|
|
// walk arg and return types
|
|
|
|
for arg in decl.inputs.iter() {
|
2014-09-12 13:10:30 +03:00
|
|
|
self.visit_ty(&*arg.ty);
|
2014-02-05 17:31:33 +13:00
|
|
|
}
|
2014-11-09 16:14:15 +01:00
|
|
|
|
|
|
|
if let ast::Return(ref ret_ty) = decl.output {
|
|
|
|
self.visit_ty(&**ret_ty);
|
|
|
|
}
|
2014-02-05 17:31:33 +13:00
|
|
|
|
|
|
|
// walk the body
|
2014-09-07 20:09:06 +03:00
|
|
|
self.nest(ex.id, |v| v.visit_block(&**body));
|
2014-02-05 17:31:33 +13:00
|
|
|
},
|
|
|
|
_ => {
|
2014-09-12 13:10:30 +03:00
|
|
|
visit::walk_expr(self, ex)
|
2014-02-05 17:31:33 +13:00
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-12 13:10:30 +03:00
|
|
|
fn visit_mac(&mut self, _: &ast::Mac) {
|
2014-02-05 17:31:33 +13:00
|
|
|
// Just stop, macros are poison to us.
|
|
|
|
}
|
|
|
|
|
2014-09-12 13:10:30 +03:00
|
|
|
fn visit_pat(&mut self, p: &ast::Pat) {
|
|
|
|
self.process_pat(p);
|
2014-02-05 17:31:33 +13:00
|
|
|
if !self.collecting {
|
|
|
|
self.collected_paths.clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-12 13:10:30 +03:00
|
|
|
fn visit_arm(&mut self, arm: &ast::Arm) {
|
2014-02-05 17:31:33 +13:00
|
|
|
assert!(self.collected_paths.len() == 0 && !self.collecting);
|
|
|
|
self.collecting = true;
|
|
|
|
|
|
|
|
for pattern in arm.pats.iter() {
|
|
|
|
// collect paths from the arm's patterns
|
2014-09-12 13:10:30 +03:00
|
|
|
self.visit_pat(&**pattern);
|
2014-02-05 17:31:33 +13:00
|
|
|
}
|
|
|
|
self.collecting = false;
|
|
|
|
// process collected paths
|
|
|
|
for &(id, ref p, ref immut, ref_kind) in self.collected_paths.iter() {
|
|
|
|
let value = if *immut {
|
2014-07-16 22:37:28 +02:00
|
|
|
self.span.snippet(p.span).into_string()
|
2014-02-05 17:31:33 +13:00
|
|
|
} else {
|
2014-07-16 22:37:28 +02:00
|
|
|
"<mutable>".to_string()
|
2014-02-05 17:31:33 +13:00
|
|
|
};
|
|
|
|
let sub_span = self.span.span_for_first_ident(p.span);
|
|
|
|
let def_map = self.analysis.ty_cx.def_map.borrow();
|
|
|
|
if !def_map.contains_key(&id) {
|
|
|
|
self.sess.span_bug(p.span,
|
|
|
|
format!("def_map has no key for {} in visit_arm",
|
|
|
|
id).as_slice());
|
|
|
|
}
|
2014-10-14 23:05:01 -07:00
|
|
|
let def = &(*def_map)[id];
|
2014-02-05 17:31:33 +13:00
|
|
|
match *def {
|
2014-09-17 18:17:09 +03:00
|
|
|
def::DefLocal(id) => self.fmt.variable_str(p.span,
|
|
|
|
sub_span,
|
|
|
|
id,
|
|
|
|
path_to_string(p).as_slice(),
|
|
|
|
value.as_slice(),
|
|
|
|
""),
|
2014-02-05 17:31:33 +13:00
|
|
|
def::DefVariant(_,id,_) => self.fmt.ref_str(ref_kind,
|
|
|
|
p.span,
|
|
|
|
sub_span,
|
|
|
|
id,
|
2014-09-12 13:10:30 +03:00
|
|
|
self.cur_scope),
|
2014-02-05 17:31:33 +13:00
|
|
|
// FIXME(nrc) what is this doing here?
|
|
|
|
def::DefStatic(_, _) => {}
|
rustc: Add `const` globals to the language
This change is an implementation of [RFC 69][rfc] which adds a third kind of
global to the language, `const`. This global is most similar to what the old
`static` was, and if you're unsure about what to use then you should use a
`const`.
The semantics of these three kinds of globals are:
* A `const` does not represent a memory location, but only a value. Constants
are translated as rvalues, which means that their values are directly inlined
at usage location (similar to a #define in C/C++). Constant values are, well,
constant, and can not be modified. Any "modification" is actually a
modification to a local value on the stack rather than the actual constant
itself.
Almost all values are allowed inside constants, whether they have interior
mutability or not. There are a few minor restrictions listed in the RFC, but
they should in general not come up too often.
* A `static` now always represents a memory location (unconditionally). Any
references to the same `static` are actually a reference to the same memory
location. Only values whose types ascribe to `Sync` are allowed in a `static`.
This restriction is in place because many threads may access a `static`
concurrently. Lifting this restriction (and allowing unsafe access) is a
future extension not implemented at this time.
* A `static mut` continues to always represent a memory location. All references
to a `static mut` continue to be `unsafe`.
This is a large breaking change, and many programs will need to be updated
accordingly. A summary of the breaking changes is:
* Statics may no longer be used in patterns. Statics now always represent a
memory location, which can sometimes be modified. To fix code, repurpose the
matched-on-`static` to a `const`.
static FOO: uint = 4;
match n {
FOO => { /* ... */ }
_ => { /* ... */ }
}
change this code to:
const FOO: uint = 4;
match n {
FOO => { /* ... */ }
_ => { /* ... */ }
}
* Statics may no longer refer to other statics by value. Due to statics being
able to change at runtime, allowing them to reference one another could
possibly lead to confusing semantics. If you are in this situation, use a
constant initializer instead. Note, however, that statics may reference other
statics by address, however.
* Statics may no longer be used in constant expressions, such as array lengths.
This is due to the same restrictions as listed above. Use a `const` instead.
[breaking-change]
[rfc]: https://github.com/rust-lang/rfcs/pull/246
2014-10-06 08:17:01 -07:00
|
|
|
def::DefConst(..) => {}
|
2014-10-15 02:25:34 -04:00
|
|
|
_ => error!("unexpected definition kind when processing collected paths: {}",
|
2014-09-07 21:47:55 +02:00
|
|
|
*def)
|
2014-02-05 17:31:33 +13:00
|
|
|
}
|
|
|
|
}
|
|
|
|
self.collected_paths.clear();
|
2014-09-10 01:54:36 +03:00
|
|
|
visit::walk_expr_opt(self, &arm.guard);
|
2014-09-12 13:10:30 +03:00
|
|
|
self.visit_expr(&*arm.body);
|
2014-02-05 17:31:33 +13:00
|
|
|
}
|
|
|
|
|
2014-09-10 01:54:36 +03:00
|
|
|
fn visit_stmt(&mut self, s: &ast::Stmt) {
|
2014-02-05 17:31:33 +13:00
|
|
|
if generated_code(s.span) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2014-09-12 13:10:30 +03:00
|
|
|
visit::walk_stmt(self, s)
|
2014-02-05 17:31:33 +13:00
|
|
|
}
|
|
|
|
|
2014-09-10 01:54:36 +03:00
|
|
|
fn visit_local(&mut self, l: &ast::Local) {
|
2014-02-05 17:31:33 +13:00
|
|
|
if generated_code(l.span) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// The local could declare multiple new vars, we must walk the
|
|
|
|
// pattern and collect them all.
|
|
|
|
assert!(self.collected_paths.len() == 0 && !self.collecting);
|
|
|
|
self.collecting = true;
|
2014-09-12 13:10:30 +03:00
|
|
|
self.visit_pat(&*l.pat);
|
2014-02-05 17:31:33 +13:00
|
|
|
self.collecting = false;
|
|
|
|
|
|
|
|
let value = self.span.snippet(l.span);
|
|
|
|
|
|
|
|
for &(id, ref p, ref immut, _) in self.collected_paths.iter() {
|
2014-07-16 22:37:28 +02:00
|
|
|
let value = if *immut { value.to_string() } else { "<mutable>".to_string() };
|
2014-02-05 17:31:33 +13:00
|
|
|
let types = self.analysis.ty_cx.node_types.borrow();
|
2014-11-10 00:59:56 +02:00
|
|
|
let typ = ppaux::ty_to_string(&self.analysis.ty_cx, (*types)[id]);
|
2014-02-05 17:31:33 +13:00
|
|
|
// Get the span only for the name of the variable (I hope the path
|
|
|
|
// is only ever a variable name, but who knows?).
|
|
|
|
let sub_span = self.span.span_for_last_ident(p.span);
|
|
|
|
// Rust uses the id of the pattern for var lookups, so we'll use it too.
|
|
|
|
self.fmt.variable_str(p.span,
|
|
|
|
sub_span,
|
|
|
|
id,
|
2014-06-21 03:39:03 -07:00
|
|
|
path_to_string(p).as_slice(),
|
2014-02-05 17:31:33 +13:00
|
|
|
value.as_slice(),
|
|
|
|
typ.as_slice());
|
|
|
|
}
|
|
|
|
self.collected_paths.clear();
|
|
|
|
|
|
|
|
// Just walk the initialiser and type (don't want to walk the pattern again).
|
2014-09-12 13:10:30 +03:00
|
|
|
self.visit_ty(&*l.ty);
|
2014-09-10 01:54:36 +03:00
|
|
|
visit::walk_expr_opt(self, &l.init);
|
2014-02-05 17:31:33 +13:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn process_crate(sess: &Session,
|
|
|
|
krate: &ast::Crate,
|
|
|
|
analysis: &CrateAnalysis,
|
|
|
|
odir: &Option<Path>) {
|
|
|
|
if generated_code(krate.span) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-06-06 13:21:18 -07:00
|
|
|
let cratename = match attr::find_crate_name(krate.attrs.as_slice()) {
|
|
|
|
Some(name) => name.get().to_string(),
|
2014-02-05 17:31:33 +13:00
|
|
|
None => {
|
|
|
|
info!("Could not find crate name, using 'unknown_crate'");
|
2014-06-06 13:21:18 -07:00
|
|
|
String::from_str("unknown_crate")
|
2014-02-05 17:31:33 +13:00
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2014-06-06 13:21:18 -07:00
|
|
|
info!("Dumping crate {}", cratename);
|
2014-02-05 17:31:33 +13:00
|
|
|
|
|
|
|
// find a path to dump our data to
|
|
|
|
let mut root_path = match os::getenv("DXR_RUST_TEMP_FOLDER") {
|
|
|
|
Some(val) => Path::new(val),
|
|
|
|
None => match *odir {
|
|
|
|
Some(ref val) => val.join("dxr"),
|
|
|
|
None => Path::new("dxr-temp"),
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2014-10-06 16:08:46 +13:00
|
|
|
match fs::mkdir_recursive(&root_path, io::USER_RWX) {
|
2014-02-05 17:31:33 +13:00
|
|
|
Err(e) => sess.err(format!("Could not create directory {}: {}",
|
|
|
|
root_path.display(), e).as_slice()),
|
|
|
|
_ => (),
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
let disp = root_path.display();
|
|
|
|
info!("Writing output to {}", disp);
|
|
|
|
}
|
|
|
|
|
2014-07-02 21:27:07 -04:00
|
|
|
// Create output file.
|
2014-02-05 17:31:33 +13:00
|
|
|
let mut out_name = cratename.clone();
|
|
|
|
out_name.push_str(".csv");
|
|
|
|
root_path.push(out_name);
|
|
|
|
let output_file = match File::create(&root_path) {
|
|
|
|
Ok(f) => box f,
|
|
|
|
Err(e) => {
|
|
|
|
let disp = root_path.display();
|
|
|
|
sess.fatal(format!("Could not open {}: {}", disp, e).as_slice());
|
|
|
|
}
|
|
|
|
};
|
|
|
|
root_path.pop();
|
|
|
|
|
2014-09-12 13:10:30 +03:00
|
|
|
let mut visitor = DxrVisitor {
|
|
|
|
sess: sess,
|
|
|
|
analysis: analysis,
|
|
|
|
collected_paths: vec!(),
|
|
|
|
collecting: false,
|
|
|
|
fmt: FmtStrs::new(box Recorder {
|
|
|
|
out: output_file as Box<Writer+'static>,
|
|
|
|
dump_spans: false,
|
|
|
|
},
|
|
|
|
SpanUtils {
|
|
|
|
sess: sess,
|
|
|
|
err_count: Cell::new(0)
|
|
|
|
},
|
|
|
|
cratename.clone()),
|
|
|
|
span: SpanUtils {
|
|
|
|
sess: sess,
|
|
|
|
err_count: Cell::new(0)
|
|
|
|
},
|
|
|
|
cur_scope: 0
|
|
|
|
};
|
2014-02-05 17:31:33 +13:00
|
|
|
|
|
|
|
visitor.dump_crate_info(cratename.as_slice(), krate);
|
|
|
|
|
2014-09-12 13:10:30 +03:00
|
|
|
visit::walk_crate(&mut visitor, krate);
|
2014-02-05 17:31:33 +13:00
|
|
|
}
|