- ln -nsf /usr/bin/llvm-dis-$LLVM_VERSION local-llvm/bin/llvm-dis
- ln -nsf /usr/bin/llc-$LLVM_VERSION local-llvm/bin/llc
- ln -nsf /usr/include/llvm-$LLVM_VERSION local-llvm/include
- - ./configure --disable-optimize-tests --llvm-root=`pwd`/local-llvm --enable-fast-make --enable-clang
+ - ./configure --disable-optimize-tests --llvm-root=`pwd`/local-llvm
+ --enable-fast-make --enable-clang
# Tidy everything up first, then build a few things, and then run a few tests.
# Note that this is meant to run in a "fairly small" amount of time, so this
valopt prefix "/usr/local" "set installation prefix"
valopt local-rust-root "/usr/local" "set prefix for local rust binary"
valopt llvm-root "" "set LLVM root"
+valopt jemalloc-root "" "set directory where libjemalloc_pic.a is located"
+valopt libuv-root "" "set directory where libuv.a is located"
valopt android-cross-path "/opt/ndk_standalone" "Android NDK standalone path"
valopt mingw32-cross-path "" "MinGW32 cross compiler path"
putvar CFG_MINGW32_CROSS_PATH
putvar CFG_MANDIR
putvar CFG_DISABLE_INJECT_STD_VERSION
+putvar CFG_JEMALLOC_ROOT
+putvar CFG_LIBUV_ROOT
# Avoid spurious warnings from clang by feeding it original source on
# ccache-miss rather than preprocessed input.
# theory when we support msvc then we should be using gyp's msvc output instead
# of mingw's makefile for windows
ifdef CFG_WINDOWSY_$(1)
-$$(LIBUV_LIB_$(1)): $$(LIBUV_DEPS) $$(MKFILE_DEPS)
+LIBUV_LOCAL_$(1) := $$(S)src/libuv/libuv.a
+$$(LIBUV_LOCAL_$(1)): $$(LIBUV_DEPS) $$(MKFILE_DEPS)
$$(Q)$$(MAKE) -C $$(S)src/libuv -f Makefile.mingw \
LDFLAGS="$$(CFG_GCCISH_LINK_FLAGS_$(1))" \
CC="$$(CC_$(1)) $$(LIBUV_CFLAGS_$(1)) $$(SNAP_DEFINES)" \
CXX="$$(CXX_$(1))" \
AR="$$(AR_$(1))" \
V=$$(VERBOSE)
- $$(Q)cp $$(S)src/libuv/libuv.a $$@
else
-$$(LIBUV_LIB_$(1)): $$(LIBUV_DIR_$(1))/Release/libuv.a $$(MKFILE_DEPS)
- $$(Q)cp $$< $$@
-$$(LIBUV_DIR_$(1))/Release/libuv.a: $$(LIBUV_DEPS) $$(LIBUV_MAKEFILE_$(1)) \
- $$(MKFILE_DEPS)
+LIBUV_LOCAL_$(1) := $$(LIBUV_DIR_$(1))/Release/libuv.a
+$$(LIBUV_LOCAL_$(1)): $$(LIBUV_DEPS) $$(LIBUV_MAKEFILE_$(1)) $$(MKFILE_DEPS)
$$(Q)$$(MAKE) -C $$(LIBUV_DIR_$(1)) \
CFLAGS="$$(LIBUV_CFLAGS_$(1)) $$(SNAP_DEFINES)" \
LDFLAGS="$$(CFG_GCCISH_LINK_FLAGS_$(1))" \
endif
+ifeq ($(1),$$(CFG_BUILD))
+ifneq ($$(CFG_LIBUV_ROOT),)
+$$(LIBUV_LIB_$(1)): $$(CFG_LIBUV_ROOT)/libuv.a
+ $$(Q)cp $$< $$@
+else
+$$(LIBUV_LIB_$(1)): $$(LIBUV_LOCAL_$(1))
+ $$(Q)cp $$< $$@
+endif
+else
+$$(LIBUV_LIB_$(1)): $$(LIBUV_LOCAL_$(1))
+ $$(Q)cp $$< $$@
+endif
+
################################################################################
# jemalloc
################################################################################
endif
JEMALLOC_LIB_$(1) := $$(RT_OUTPUT_DIR_$(1))/$$(JEMALLOC_NAME_$(1))
JEMALLOC_BUILD_DIR_$(1) := $$(RT_OUTPUT_DIR_$(1))/jemalloc
+JEMALLOC_LOCAL_$(1) := $$(JEMALLOC_BUILD_DIR_$(1))/lib/$$(JEMALLOC_REAL_NAME_$(1))
-$$(JEMALLOC_LIB_$(1)): $$(JEMALLOC_DEPS) $$(MKFILE_DEPS)
+$$(JEMALLOC_LOCAL_$(1)): $$(JEMALLOC_DEPS) $$(MKFILE_DEPS)
@$$(call E, make: jemalloc)
cd "$$(JEMALLOC_BUILD_DIR_$(1))"; "$(S)src/jemalloc/configure" \
$$(JEMALLOC_ARGS_$(1)) --enable-cc-silence --with-jemalloc-prefix=je_ \
CPPFLAGS="-I $(S)src/rt/" \
EXTRA_CFLAGS="$$(CFG_CFLAGS_$(1)) -g1"
$$(Q)$$(MAKE) -C "$$(JEMALLOC_BUILD_DIR_$(1))" build_lib_static
- $$(Q)cp $$(JEMALLOC_BUILD_DIR_$(1))/lib/$$(JEMALLOC_REAL_NAME_$(1)) $$(JEMALLOC_LIB_$(1))
+
+ifeq ($(1),$$(CFG_BUILD))
+ifneq ($$(CFG_JEMALLOC_ROOT),)
+$$(JEMALLOC_LIB_$(1)): $$(CFG_JEMALLOC_ROOT)/libjemalloc_pic.a
+ @$$(call E, copy: jemalloc)
+ $$(Q)cp $$< $$@
+else
+$$(JEMALLOC_LIB_$(1)): $$(JEMALLOC_LOCAL_$(1))
+ $$(Q)cp $$< $$@
+endif
+else
+$$(JEMALLOC_LIB_$(1)): $$(JEMALLOC_LOCAL_$(1))
+ $$(Q)cp $$< $$@
+endif
################################################################################
# compiler-rt
name for the same data.
In the case of `on_the_heap`, however, no explicit action is necessary.
-The compiler will automatically convert a box box point to a reference like &point.
+The compiler will automatically convert a box point to a reference like &point.
This is another form of borrowing; in this case, the contents of the owned box
are being lent out.
# Borrowing and enums
-The previous example showed that the type system forbids any borrowing
-of owned boxes found in aliasable, mutable memory. This restriction
+The previous example showed that the type system forbids any mutations
+of owned boxed values while they are being borrowed. In general, the type
+system also forbids borrowing a value as mutable if it is already being
+borrowed - either as a mutable reference or an immutable one. This restriction
prevents pointers from pointing into freed memory. There is one other
case where the compiler must be very careful to ensure that pointers
remain valid: pointers into the interior of an `enum`.
line_comment : "//" non_eol * ;
~~~~
-Comments in Rust code follow the general C++ style of line and block-comment forms,
-with no nesting of block-comment delimiters.
+Comments in Rust code follow the general C++ style of line and block-comment forms.
+Nested block comments are supported.
Line comments beginning with exactly _three_ slashes (`///`), and block
comments beginning with exactly one repeated asterisk in the block-open
}
~~~~
-In this example, there is no type parameter. Instead, the `~Drawable`
+In this example, there is no type parameter. Instead, the `Box<Drawable>`
type denotes any owned box value that implements the `Drawable` trait.
To construct such a value, you use the `as` operator to cast a value
to an object:
alloc as *mut u8
}
-// hack for libcore
-#[no_mangle]
-#[doc(hidden)]
-#[deprecated]
-#[cfg(not(test))]
-pub unsafe extern "C" fn rust_allocate(size: uint, align: uint) -> *mut u8 {
- allocate(size, align)
-}
-
-// hack for libcore
-#[no_mangle]
-#[doc(hidden)]
-#[deprecated]
-#[cfg(not(test))]
-pub unsafe extern "C" fn rust_deallocate(ptr: *mut u8, size: uint, align: uint) {
- deallocate(ptr, size, align)
-}
-
#[cfg(test)]
mod bench {
extern crate test;
box 10
})
}
-
- #[bench]
- fn alloc_owned_big(b: &mut Bencher) {
- b.iter(|| {
- box [10, ..1000]
- })
- }
}
}
}
-impl<S: Writer, T: Hash<S>> Hash<S> for ~[T] {
- #[inline]
- fn hash(&self, state: &mut S) {
- self.as_slice().hash(state);
- }
-}
-
impl<S: Writer, T: Hash<S>> Hash<S> for Vec<T> {
#[inline]
fn hash(&self, state: &mut S) {
use str::Str;
use string::String;
use slice::{Vector, ImmutableVector};
+ use vec::Vec;
use super::super::{Hash, Writer};
use super::{SipState, hash, hash_with_keys};
s
}
- fn result_bytes(h: u64) -> ~[u8] {
- box [(h >> 0) as u8,
+ fn result_bytes(h: u64) -> Vec<u8> {
+ vec![(h >> 0) as u8,
(h >> 8) as u8,
(h >> 16) as u8,
(h >> 24) as u8,
use core::prelude::*;
-use alloc::heap::{allocate, deallocate};
use core::cmp;
-use core::finally::try_finally;
use core::mem::size_of;
-use core::mem::transmute;
use core::mem;
use core::ptr;
use core::iter::{range_step, MultiplicativeIterator};
/// Generates even and odd permutations alternately.
pub struct Permutations<T> {
swaps: ElementSwaps,
- v: ~[T],
+ v: Vec<T>,
}
-impl<T: Clone> Iterator<~[T]> for Permutations<T> {
+impl<T: Clone> Iterator<Vec<T>> for Permutations<T> {
#[inline]
- fn next(&mut self) -> Option<~[T]> {
+ fn next(&mut self) -> Option<Vec<T>> {
match self.swaps.next() {
None => None,
Some((0,0)) => Some(self.v.clone()),
Some((a, b)) => {
let elt = self.v.clone();
- self.v.swap(a, b);
+ self.v.as_mut_slice().swap(a, b);
Some(elt)
}
}
/// Extension methods for vector slices with cloneable elements
pub trait CloneableVector<T> {
/// Copy `self` into a new owned vector
- fn to_owned(&self) -> ~[T];
+ fn to_owned(&self) -> Vec<T>;
/// Convert `self` into an owned vector, not making a copy if possible.
- fn into_owned(self) -> ~[T];
+ fn into_owned(self) -> Vec<T>;
}
/// Extension methods for vector slices
impl<'a, T: Clone> CloneableVector<T> for &'a [T] {
/// Returns a copy of `v`.
#[inline]
- fn to_owned(&self) -> ~[T] {
- use RawVec = core::raw::Vec;
- use core::num::{CheckedAdd, CheckedMul};
- use core::ptr;
-
- let len = self.len();
- let data_size = len.checked_mul(&mem::size_of::<T>());
- let data_size = data_size.expect("overflow in to_owned()");
- let size = mem::size_of::<RawVec<()>>().checked_add(&data_size);
- let size = size.expect("overflow in to_owned()");
-
- unsafe {
- // this should pass the real required alignment
- let ret = allocate(size, 8) as *mut RawVec<()>;
-
- let a_size = mem::size_of::<T>();
- let a_size = if a_size == 0 {1} else {a_size};
- (*ret).fill = len * a_size;
- (*ret).alloc = len * a_size;
-
- // Be careful with the following loop. We want it to be optimized
- // to a memcpy (or something similarly fast) when T is Copy. LLVM
- // is easily confused, so any extra operations during the loop can
- // prevent this optimization.
- let mut i = 0;
- let p = &mut (*ret).data as *mut _ as *mut T;
- try_finally(
- &mut i, (),
- |i, ()| while *i < len {
- ptr::write(
- &mut(*p.offset(*i as int)),
- self.unsafe_ref(*i).clone());
- *i += 1;
- },
- |i| if *i < len {
- // we must be failing, clean up after ourselves
- for j in range(0, *i as int) {
- ptr::read(&*p.offset(j));
- }
- // FIXME: #13994 (should pass align and size here)
- deallocate(ret as *mut u8, 0, 8);
- });
- mem::transmute(ret)
- }
- }
+ fn to_owned(&self) -> Vec<T> { Vec::from_slice(*self) }
#[inline(always)]
- fn into_owned(self) -> ~[T] { self.to_owned() }
-}
-
-/// Extension methods for owned vectors
-impl<T: Clone> CloneableVector<T> for ~[T] {
- #[inline]
- fn to_owned(&self) -> ~[T] { self.clone() }
-
- #[inline(always)]
- fn into_owned(self) -> ~[T] { self }
+ fn into_owned(self) -> Vec<T> { self.to_owned() }
}
/// Extension methods for vectors containing `Clone` elements.
}
-/// Extension methods for owned vectors.
-pub trait OwnedVector<T> {
- /// Creates a consuming iterator, that is, one that moves each
- /// value out of the vector (from start to end). The vector cannot
- /// be used after calling this.
- ///
- /// # Examples
- ///
- /// ```rust
- /// let v = ~["a".to_string(), "b".to_string()];
- /// for s in v.move_iter() {
- /// // s has type ~str, not &~str
- /// println!("{}", s);
- /// }
- /// ```
- fn move_iter(self) -> MoveItems<T>;
-
- /**
- * Partitions the vector into two vectors `(A,B)`, where all
- * elements of `A` satisfy `f` and all elements of `B` do not.
- */
- fn partition(self, f: |&T| -> bool) -> (Vec<T>, Vec<T>);
-}
-
-impl<T> OwnedVector<T> for ~[T] {
- #[inline]
- fn move_iter(self) -> MoveItems<T> {
- unsafe {
- let iter = transmute(self.iter());
- let ptr = transmute(self);
- MoveItems { allocation: ptr, iter: iter }
- }
- }
-
- #[inline]
- fn partition(self, f: |&T| -> bool) -> (Vec<T>, Vec<T>) {
- let mut lefts = Vec::new();
- let mut rights = Vec::new();
-
- for elt in self.move_iter() {
- if f(&elt) {
- lefts.push(elt);
- } else {
- rights.push(elt);
- }
- }
-
- (lefts, rights)
- }
-}
-
fn insertion_sort<T>(v: &mut [T], compare: |&T, &T| -> Ordering) {
let len = v.len() as int;
let buf_v = v.as_mut_ptr();
* * start - The index into `src` to start copying from
* * end - The index into `str` to stop copying from
*/
- fn move_from(self, src: ~[T], start: uint, end: uint) -> uint;
+ fn move_from(self, src: Vec<T>, start: uint, end: uint) -> uint;
}
impl<'a,T> MutableVectorAllocating<'a, T> for &'a mut [T] {
}
#[inline]
- fn move_from(self, mut src: ~[T], start: uint, end: uint) -> uint {
+ fn move_from(self, mut src: Vec<T>, start: uint, end: uint) -> uint {
for (a, b) in self.mut_iter().zip(src.mut_slice(start, end).mut_iter()) {
mem::swap(a, b);
}
pub use core::slice::raw::{shift_ptr, pop_ptr};
}
-/// An iterator that moves out of a vector.
-pub struct MoveItems<T> {
- allocation: *mut u8, // the block of memory allocated for the vector
- iter: Items<'static, T>
-}
-
-impl<T> Iterator<T> for MoveItems<T> {
- #[inline]
- fn next(&mut self) -> Option<T> {
- unsafe {
- self.iter.next().map(|x| ptr::read(x))
- }
- }
-
- #[inline]
- fn size_hint(&self) -> (uint, Option<uint>) {
- self.iter.size_hint()
- }
-}
-
-impl<T> DoubleEndedIterator<T> for MoveItems<T> {
- #[inline]
- fn next_back(&mut self) -> Option<T> {
- unsafe {
- self.iter.next_back().map(|x| ptr::read(x))
- }
- }
-}
-
-#[unsafe_destructor]
-impl<T> Drop for MoveItems<T> {
- fn drop(&mut self) {
- // destroy the remaining elements
- for _x in *self {}
- unsafe {
- // FIXME: #13994 (should pass align and size here)
- deallocate(self.allocation, 0, 8)
- }
- }
-}
-
#[cfg(test)]
mod tests {
use std::cell::Cell;
#[test]
fn test_get() {
- let mut a = box [11];
- assert_eq!(a.get(1), None);
- a = box [11, 12];
- assert_eq!(a.get(1).unwrap(), &12);
- a = box [11, 12, 13];
- assert_eq!(a.get(1).unwrap(), &12);
+ let mut a = vec![11];
+ assert_eq!(a.as_slice().get(1), None);
+ a = vec![11, 12];
+ assert_eq!(a.as_slice().get(1).unwrap(), &12);
+ a = vec![11, 12, 13];
+ assert_eq!(a.as_slice().get(1).unwrap(), &12);
}
#[test]
fn test_head() {
- let mut a = box [];
- assert_eq!(a.head(), None);
- a = box [11];
- assert_eq!(a.head().unwrap(), &11);
- a = box [11, 12];
- assert_eq!(a.head().unwrap(), &11);
+ let mut a = vec![];
+ assert_eq!(a.as_slice().head(), None);
+ a = vec![11];
+ assert_eq!(a.as_slice().head().unwrap(), &11);
+ a = vec![11, 12];
+ assert_eq!(a.as_slice().head().unwrap(), &11);
}
#[test]
fn test_tail() {
- let mut a = box [11];
+ let mut a = vec![11];
assert_eq!(a.tail(), &[]);
- a = box [11, 12];
+ a = vec![11, 12];
assert_eq!(a.tail(), &[12]);
}
#[test]
#[should_fail]
fn test_tail_empty() {
- let a: ~[int] = box [];
+ let a: Vec<int> = vec![];
a.tail();
}
#[test]
fn test_tailn() {
- let mut a = box [11, 12, 13];
+ let mut a = vec![11, 12, 13];
assert_eq!(a.tailn(0), &[11, 12, 13]);
- a = box [11, 12, 13];
+ a = vec![11, 12, 13];
assert_eq!(a.tailn(2), &[13]);
}
#[test]
#[should_fail]
fn test_tailn_empty() {
- let a: ~[int] = box [];
+ let a: Vec<int> = vec![];
a.tailn(2);
}
#[test]
fn test_init() {
- let mut a = box [11];
+ let mut a = vec![11];
assert_eq!(a.init(), &[]);
- a = box [11, 12];
+ a = vec![11, 12];
assert_eq!(a.init(), &[11]);
}
#[test]
#[should_fail]
fn test_init_empty() {
- let a: ~[int] = box [];
+ let a: Vec<int> = vec![];
a.init();
}
#[test]
fn test_initn() {
- let mut a = box [11, 12, 13];
- assert_eq!(a.initn(0), &[11, 12, 13]);
- a = box [11, 12, 13];
- assert_eq!(a.initn(2), &[11]);
+ let mut a = vec![11, 12, 13];
+ assert_eq!(a.as_slice().initn(0), &[11, 12, 13]);
+ a = vec![11, 12, 13];
+ assert_eq!(a.as_slice().initn(2), &[11]);
}
#[test]
#[should_fail]
fn test_initn_empty() {
- let a: ~[int] = box [];
- a.initn(2);
+ let a: Vec<int> = vec![];
+ a.as_slice().initn(2);
}
#[test]
fn test_last() {
- let mut a = box [];
- assert_eq!(a.last(), None);
- a = box [11];
- assert_eq!(a.last().unwrap(), &11);
- a = box [11, 12];
- assert_eq!(a.last().unwrap(), &12);
+ let mut a = vec![];
+ assert_eq!(a.as_slice().last(), None);
+ a = vec![11];
+ assert_eq!(a.as_slice().last().unwrap(), &11);
+ a = vec![11, 12];
+ assert_eq!(a.as_slice().last().unwrap(), &12);
}
#[test]
let vec_fixed = [1, 2, 3, 4];
let v_a = vec_fixed.slice(1u, vec_fixed.len()).to_owned();
assert_eq!(v_a.len(), 3u);
+ let v_a = v_a.as_slice();
assert_eq!(v_a[0], 2);
assert_eq!(v_a[1], 3);
assert_eq!(v_a[2], 4);
let vec_stack = &[1, 2, 3];
let v_b = vec_stack.slice(1u, 3u).to_owned();
assert_eq!(v_b.len(), 2u);
+ let v_b = v_b.as_slice();
assert_eq!(v_b[0], 2);
assert_eq!(v_b[1], 3);
// Test `Box<[T]>`
- let vec_unique = box [1, 2, 3, 4, 5, 6];
+ let vec_unique = vec![1, 2, 3, 4, 5, 6];
let v_d = vec_unique.slice(1u, 6u).to_owned();
assert_eq!(v_d.len(), 5u);
+ let v_d = v_d.as_slice();
assert_eq!(v_d[0], 2);
assert_eq!(v_d[1], 3);
assert_eq!(v_d[2], 4);
let (min_size, max_opt) = it.size_hint();
assert_eq!(min_size, 3*2);
assert_eq!(max_opt.unwrap(), 3*2);
- assert_eq!(it.next(), Some(box [1,2,3]));
- assert_eq!(it.next(), Some(box [1,3,2]));
- assert_eq!(it.next(), Some(box [3,1,2]));
+ assert_eq!(it.next(), Some(vec![1,2,3]));
+ assert_eq!(it.next(), Some(vec![1,3,2]));
+ assert_eq!(it.next(), Some(vec![3,1,2]));
let (min_size, max_opt) = it.size_hint();
assert_eq!(min_size, 3);
assert_eq!(max_opt.unwrap(), 3);
- assert_eq!(it.next(), Some(box [3,2,1]));
- assert_eq!(it.next(), Some(box [2,3,1]));
- assert_eq!(it.next(), Some(box [2,1,3]));
+ assert_eq!(it.next(), Some(vec![3,2,1]));
+ assert_eq!(it.next(), Some(vec![2,3,1]));
+ assert_eq!(it.next(), Some(vec![2,1,3]));
assert_eq!(it.next(), None);
}
{
fn test_position_elem() {
assert!([].position_elem(&1).is_none());
- let v1 = box [1, 2, 3, 3, 2, 5];
- assert_eq!(v1.position_elem(&1), Some(0u));
- assert_eq!(v1.position_elem(&2), Some(1u));
- assert_eq!(v1.position_elem(&5), Some(5u));
- assert!(v1.position_elem(&4).is_none());
+ let v1 = vec![1, 2, 3, 3, 2, 5];
+ assert_eq!(v1.as_slice().position_elem(&1), Some(0u));
+ assert_eq!(v1.as_slice().position_elem(&2), Some(1u));
+ assert_eq!(v1.as_slice().position_elem(&5), Some(5u));
+ assert!(v1.as_slice().position_elem(&4).is_none());
}
#[test]
#[test]
fn test_reverse() {
- let mut v: ~[int] = box [10, 20];
- assert_eq!(v[0], 10);
- assert_eq!(v[1], 20);
+ let mut v: Vec<int> = vec![10, 20];
+ assert_eq!(*v.get(0), 10);
+ assert_eq!(*v.get(1), 20);
v.reverse();
- assert_eq!(v[0], 20);
- assert_eq!(v[1], 10);
+ assert_eq!(*v.get(0), 20);
+ assert_eq!(*v.get(1), 10);
- let mut v3: ~[int] = box [];
+ let mut v3: Vec<int> = vec![];
v3.reverse();
assert!(v3.is_empty());
}
#[test]
fn test_partition() {
- assert_eq!((box []).partition(|x: &int| *x < 3), (vec![], vec![]));
- assert_eq!((box [1, 2, 3]).partition(|x: &int| *x < 4), (vec![1, 2, 3], vec![]));
- assert_eq!((box [1, 2, 3]).partition(|x: &int| *x < 2), (vec![1], vec![2, 3]));
- assert_eq!((box [1, 2, 3]).partition(|x: &int| *x < 0), (vec![], vec![1, 2, 3]));
+ assert_eq!((vec![]).partition(|x: &int| *x < 3), (vec![], vec![]));
+ assert_eq!((vec![1, 2, 3]).partition(|x: &int| *x < 4), (vec![1, 2, 3], vec![]));
+ assert_eq!((vec![1, 2, 3]).partition(|x: &int| *x < 2), (vec![1], vec![2, 3]));
+ assert_eq!((vec![1, 2, 3]).partition(|x: &int| *x < 0), (vec![], vec![1, 2, 3]));
}
#[test]
#[test]
fn test_concat() {
- let v: [~[int], ..0] = [];
+ let v: [Vec<int>, ..0] = [];
assert_eq!(v.concat_vec(), vec![]);
- assert_eq!([box [1], box [2,3]].concat_vec(), vec![1, 2, 3]);
+ assert_eq!([vec![1], vec![2,3]].concat_vec(), vec![1, 2, 3]);
assert_eq!([&[1], &[2,3]].concat_vec(), vec![1, 2, 3]);
}
#[test]
fn test_connect() {
- let v: [~[int], ..0] = [];
+ let v: [Vec<int>, ..0] = [];
assert_eq!(v.connect_vec(&0), vec![]);
- assert_eq!([box [1], box [2, 3]].connect_vec(&0), vec![1, 0, 2, 3]);
- assert_eq!([box [1], box [2], box [3]].connect_vec(&0), vec![1, 0, 2, 0, 3]);
+ assert_eq!([vec![1], vec![2, 3]].connect_vec(&0), vec![1, 0, 2, 3]);
+ assert_eq!([vec![1], vec![2], vec![3]].connect_vec(&0), vec![1, 0, 2, 0, 3]);
assert_eq!([&[1], &[2, 3]].connect_vec(&0), vec![1, 0, 2, 3]);
assert_eq!([&[1], &[2], &[3]].connect_vec(&0), vec![1, 0, 2, 0, 3]);
#[test]
fn test_move_iterator() {
- let xs = box [1u,2,3,4,5];
+ let xs = vec![1u,2,3,4,5];
assert_eq!(xs.move_iter().fold(0, |a: uint, b: uint| 10*a + b), 12345);
}
#[test]
fn test_move_rev_iterator() {
- let xs = box [1u,2,3,4,5];
+ let xs = vec![1u,2,3,4,5];
assert_eq!(xs.move_iter().rev().fold(0, |a: uint, b: uint| 10*a + b), 54321);
}
#[test]
fn test_move_from() {
let mut a = [1,2,3,4,5];
- let b = box [6,7,8];
+ let b = vec![6,7,8];
assert_eq!(a.move_from(b, 0, 3), 3);
assert!(a == [6,7,8,4,5]);
let mut a = [7,2,8,1];
- let b = box [3,1,4,1,5,9];
+ let b = vec![3,1,4,1,5,9];
assert_eq!(a.move_from(b, 0, 6), 4);
assert!(a == [3,1,4,1]);
let mut a = [1,2,3,4];
- let b = box [5,6,7,8,9,0];
+ let b = vec![5,6,7,8,9,0];
assert_eq!(a.move_from(b, 2, 3), 1);
assert!(a == [7,2,3,4]);
let mut a = [1,2,3,4,5];
- let b = box [5,6,7,8,9,0];
+ let b = vec![5,6,7,8,9,0];
assert_eq!(a.mut_slice(2,4).move_from(b,1,6), 2);
assert!(a == [1,2,6,7,5]);
}
assert_eq!(format!("{}", x.as_slice()), x_str);
})
)
- let empty: ~[int] = box [];
+ let empty: Vec<int> = vec![];
test_show_vec!(empty, "[]".to_string());
- test_show_vec!(box [1], "[1]".to_string());
- test_show_vec!(box [1, 2, 3], "[1, 2, 3]".to_string());
- test_show_vec!(box [box [], box [1u], box [1u, 1u]],
+ test_show_vec!(vec![1], "[1]".to_string());
+ test_show_vec!(vec![1, 2, 3], "[1, 2, 3]".to_string());
+ test_show_vec!(vec![vec![], vec![1u], vec![1u, 1u]],
"[[], [1], [1, 1]]".to_string());
let empty_mut: &mut [int] = &mut[];
);
t!(&[int]);
- t!(~[int]);
t!(Vec<int>);
}
});
}
- #[bench]
- fn zero_1kb_fixed_repeat(b: &mut Bencher) {
- b.iter(|| {
- box [0u8, ..1024]
- });
- }
-
#[bench]
fn zero_1kb_loop_set(b: &mut Bencher) {
b.iter(|| {
use str::StrAllocating;
unsafe {
- let a = ~[65u8, 65u8, 65u8, 65u8, 65u8, 65u8, 65u8, 0u8];
+ let a = vec![65u8, 65u8, 65u8, 65u8, 65u8, 65u8, 65u8, 0u8];
let b = a.as_ptr();
let c = from_buf_len(b, 3u);
assert_eq!(c, "AAA".to_string());
assert!(half_a_million_letter_a() ==
unsafe {raw::slice_bytes(letters.as_slice(),
0u,
- 500000)}.to_owned());
+ 500000)}.to_string());
}
#[test]
assert_eq!("", data.slice(3, 3));
assert_eq!("华", data.slice(30, 33));
- fn a_million_letter_X() -> String {
+ fn a_million_letter_x() -> String {
let mut i = 0;
let mut rs = String::new();
while i < 100000 {
}
rs
}
- fn half_a_million_letter_X() -> String {
+ fn half_a_million_letter_x() -> String {
let mut i = 0;
let mut rs = String::new();
while i < 100000 {
}
rs
}
- let letters = a_million_letter_X();
- assert!(half_a_million_letter_X() ==
- letters.as_slice().slice(0u, 3u * 500000u).to_owned());
+ let letters = a_million_letter_x();
+ assert!(half_a_million_letter_x() ==
+ letters.as_slice().slice(0u, 3u * 500000u).to_string());
}
#[test]
#[test]
fn test_raw_from_c_str() {
unsafe {
- let a = box [65, 65, 65, 65, 65, 65, 65, 0];
+ let a = vec![65, 65, 65, 65, 65, 65, 65, 0];
let b = a.as_ptr();
let c = raw::from_c_str(b);
assert_eq!(c, "AAAAAAA".to_string());
#[test]
fn test_char_at() {
let s = "ศไทย中华Việt Nam";
- let v = box ['ศ','ไ','ท','ย','中','华','V','i','ệ','t',' ','N','a','m'];
+ let v = vec!['ศ','ไ','ท','ย','中','华','V','i','ệ','t',' ','N','a','m'];
let mut pos = 0;
for ch in v.iter() {
assert!(s.char_at(pos) == *ch);
#[test]
fn test_char_at_reverse() {
let s = "ศไทย中华Việt Nam";
- let v = box ['ศ','ไ','ท','ย','中','华','V','i','ệ','t',' ','N','a','m'];
+ let v = vec!['ศ','ไ','ท','ย','中','华','V','i','ệ','t',' ','N','a','m'];
let mut pos = s.len();
for ch in v.iter().rev() {
assert!(s.char_at_reverse(pos) == *ch);
#[test]
fn test_iterator() {
let s = "ศไทย中华Việt Nam";
- let v = box ['ศ','ไ','ท','ย','中','华','V','i','ệ','t',' ','N','a','m'];
+ let v = ['ศ','ไ','ท','ย','中','华','V','i','ệ','t',' ','N','a','m'];
let mut pos = 0;
let mut it = s.chars();
#[test]
fn test_rev_iterator() {
let s = "ศไทย中华Việt Nam";
- let v = box ['m', 'a', 'N', ' ', 't', 'ệ','i','V','华','中','ย','ท','ไ','ศ'];
+ let v = ['m', 'a', 'N', ' ', 't', 'ệ','i','V','华','中','ย','ท','ไ','ศ'];
let mut pos = 0;
let mut it = s.chars().rev();
use core::prelude::*;
use alloc::heap::{allocate, reallocate, deallocate};
-use RawVec = core::raw::Vec;
use core::raw::Slice;
use core::cmp::max;
use core::default::Default;
use core::uint;
use {Collection, Mutable};
-use slice::{MutableOrdVector, OwnedVector, MutableVectorAllocating};
+use slice::{MutableOrdVector, MutableVectorAllocating, CloneableVector};
use slice::{Items, MutItems};
/// An owned, growable vector.
impl<T: Eq> Eq for Vec<T> {}
+impl<T: PartialEq, V: Vector<T>> Equiv<V> for Vec<T> {
+ #[inline]
+ fn equiv(&self, other: &V) -> bool { self.as_slice() == other.as_slice() }
+}
+
impl<T: Ord> Ord for Vec<T> {
#[inline]
fn cmp(&self, other: &Vec<T>) -> Ordering {
}
}
+impl<T: Clone> CloneableVector<T> for Vec<T> {
+ fn to_owned(&self) -> Vec<T> { self.clone() }
+ fn into_owned(self) -> Vec<T> { self }
+}
+
// FIXME: #13996: need a way to mark the return value as `noalias`
#[inline(never)]
unsafe fn alloc_or_realloc<T>(ptr: *mut T, size: uint, old_size: uint) -> *mut T {
(ts, us)
}
-/// Mechanism to convert from a `Vec<T>` to a `[T]`.
-///
-/// In a post-DST world this will be used to convert to any `Ptr<[T]>`.
-///
-/// This could be implemented on more types than just pointers to vectors, but
-/// the recommended approach for those types is to implement `FromIterator`.
-// FIXME(#12938): Update doc comment when DST lands
-pub trait FromVec<T> {
- /// Convert a `Vec<T>` into the receiver type.
- fn from_vec(v: Vec<T>) -> Self;
-}
-
-impl<T> FromVec<T> for ~[T] {
- fn from_vec(mut v: Vec<T>) -> ~[T] {
- let len = v.len();
- let data_size = len.checked_mul(&mem::size_of::<T>());
- let data_size = data_size.expect("overflow in from_vec()");
- let size = mem::size_of::<RawVec<()>>().checked_add(&data_size);
- let size = size.expect("overflow in from_vec()");
-
- // In a post-DST world, we can attempt to reuse the Vec allocation by calling
- // shrink_to_fit() on it. That may involve a reallocation+memcpy, but that's no
- // different than what we're doing manually here.
-
- let vp = v.as_mut_ptr();
-
- unsafe {
- let ret = allocate(size, 8) as *mut RawVec<()>;
-
- let a_size = mem::size_of::<T>();
- let a_size = if a_size == 0 {1} else {a_size};
- (*ret).fill = len * a_size;
- (*ret).alloc = len * a_size;
-
- ptr::copy_nonoverlapping_memory(&mut (*ret).data as *mut _ as *mut u8,
- vp as *u8, data_size);
-
- // we've transferred ownership of the contents from v, but we can't drop it
- // as it still needs to free its own allocation.
- v.set_len(0);
-
- mem::transmute(ret)
- }
- }
-}
-
/// Unsafe operations
pub mod raw {
use super::Vec;
mod tests {
use std::prelude::*;
use std::mem::size_of;
- use std::kinds::marker;
- use super::{unzip, raw, FromVec, Vec};
+ use super::{unzip, raw, Vec};
#[test]
fn test_small_vec_struct() {
assert_eq!(b, vec![1, 2, 3]);
// Test on-heap copy-from-buf.
- let c = box [1, 2, 3, 4, 5];
+ let c = vec![1, 2, 3, 4, 5];
let ptr = c.as_ptr();
let d = raw::from_buf(ptr, 5u);
assert_eq!(d, vec![1, 2, 3, 4, 5]);
}
}
- #[test]
- fn test_from_vec() {
- let a = vec![1u, 2, 3];
- let b: ~[uint] = FromVec::from_vec(a);
- assert_eq!(b.as_slice(), &[1u, 2, 3]);
-
- let a = vec![];
- let b: ~[u8] = FromVec::from_vec(a);
- assert_eq!(b.as_slice(), &[]);
-
- let a = vec!["one".to_string(), "two".to_string()];
- let b: ~[String] = FromVec::from_vec(a);
- assert_eq!(b.as_slice(), &["one".to_string(), "two".to_string()]);
-
- struct Foo {
- x: uint,
- nocopy: marker::NoCopy
- }
-
- let a = vec![Foo{x: 42, nocopy: marker::NoCopy}, Foo{x: 84, nocopy: marker::NoCopy}];
- let b: ~[Foo] = FromVec::from_vec(a);
- assert_eq!(b.len(), 2);
- assert_eq!(b[0].x, 42);
- assert_eq!(b[1].x, 84);
- }
-
#[test]
fn test_vec_truncate_drop() {
static mut drops: uint = 0;
#[cfg(test)]
mod test {
use super::*;
+ use mem::drop;
#[test]
fn smoketest_cell() {
assert!(format!("{}", x).as_slice().contains(x.get()));
}
+ #[test]
+ fn ref_and_refmut_have_sensible_show() {
+ use str::StrSlice;
+ use realstd::str::Str;
+
+ let refcell = RefCell::new("foo");
+
+ let refcell_refmut = refcell.borrow_mut();
+ assert!(format!("{}", refcell_refmut).as_slice().contains("foo"));
+ drop(refcell_refmut);
+
+ let refcell_ref = refcell.borrow();
+ assert!(format!("{}", refcell_ref).as_slice().contains("foo"));
+ drop(refcell_ref);
+ }
+
#[test]
fn double_imm_borrow() {
let x = RefCell::new(0);
fn test_fn_a() -> f64 { 1.0 }
fn test_fn_b<T: Empty>(x: T) -> T { x }
- fn test_fn_c(_: int, _: f64, _: ~[int], _: int, _: int, _: int) {}
+ fn test_fn_c(_: int, _: f64, _: int, _: int, _: int) {}
let _ = test_fn_a.clone();
let _ = test_fn_b::<int>.clone();
#![allow(dead_code, missing_doc)]
use fmt;
-use intrinsics;
+#[cfg(not(test))] use intrinsics;
#[cold] #[inline(never)] // this is the slow path, always
#[lang="fail_"]
#![allow(unused_variable)]
use any;
-use cell::Cell;
+use cell::{Cell, Ref, RefMut};
use char::Char;
use collections::Collection;
use iter::{Iterator, range};
use kinds::Copy;
use mem;
use option::{Option, Some, None};
+use ops::Deref;
use result::{Ok, Err};
use result;
use slice::{Vector, ImmutableVector};
}
}
-impl<T: Show> Show for ~[T] {
- fn fmt(&self, f: &mut Formatter) -> Result {
- secret_show(&self.as_slice(), f)
- }
-}
-
impl Show for () {
fn fmt(&self, f: &mut Formatter) -> Result {
f.pad("()")
}
}
+impl<'b, T: Show> Show for Ref<'b, T> {
+ fn fmt(&self, f: &mut Formatter) -> Result {
+ (**self).fmt(f)
+ }
+}
+
+impl<'b, T: Show> Show for RefMut<'b, T> {
+ fn fmt(&self, f: &mut Formatter) -> Result {
+ (*(self.deref())).fmt(f)
+ }
+}
+
// If you expected tests to be here, look instead at the run-pass/ifmt.rs test,
// it's a lot easier than creating all of the rt::Piece structures here.
fn visit_char(&mut self) -> bool;
+ #[cfg(stage0)]
fn visit_estr_box(&mut self) -> bool;
+ #[cfg(stage0)]
fn visit_estr_uniq(&mut self) -> bool;
fn visit_estr_slice(&mut self) -> bool;
fn visit_estr_fixed(&mut self, n: uint, sz: uint, align: uint) -> bool;
fn visit_ptr(&mut self, mtbl: uint, inner: *TyDesc) -> bool;
fn visit_rptr(&mut self, mtbl: uint, inner: *TyDesc) -> bool;
+ #[cfg(stage0)]
fn visit_evec_box(&mut self, mtbl: uint, inner: *TyDesc) -> bool;
+ #[cfg(stage0)]
fn visit_evec_uniq(&mut self, mtbl: uint, inner: *TyDesc) -> bool;
fn visit_evec_slice(&mut self, mtbl: uint, inner: *TyDesc) -> bool;
fn visit_evec_fixed(&mut self, n: uint, sz: uint, align: uint,
translated to the `loop` below.
```rust
-let values = ~[1, 2, 3];
+let values = vec![1, 2, 3];
// "Syntactical sugar" taking advantage of an iterator
for &x in values.iter() {
/// }
/// sum
/// }
- /// let x = ~[1,2,3,7,8,9];
+ /// let x = vec![1,2,3,7,8,9];
/// assert_eq!(process(x.move_iter()), 1006);
/// ```
#[inline]
#[test]
fn test_iterator_peekable() {
- let xs = box [0u, 1, 2, 3, 4, 5];
+ let xs = vec![0u, 1, 2, 3, 4, 5];
let mut it = xs.iter().map(|&x|x).peekable();
assert_eq!(it.peek().unwrap(), &0);
assert_eq!(it.next().unwrap(), 0);
#[test]
fn test_double_ended_chain() {
let xs = [1, 2, 3, 4, 5];
- let ys = box [7, 9, 11];
+ let ys = [7, 9, 11];
let mut it = xs.iter().chain(ys.iter()).rev();
assert_eq!(it.next().unwrap(), &11)
assert_eq!(it.next().unwrap(), &9)
fn test_rposition() {
fn f(xy: &(int, char)) -> bool { let (_x, y) = *xy; y == 'b' }
fn g(xy: &(int, char)) -> bool { let (_x, y) = *xy; y == 'd' }
- let v = box [(0, 'a'), (1, 'b'), (2, 'c'), (3, 'b')];
+ let v = [(0, 'a'), (1, 'b'), (2, 'c'), (3, 'b')];
assert_eq!(v.iter().rposition(f), Some(3u));
assert!(v.iter().rposition(g).is_none());
#[test]
fn test_random_access_chain() {
let xs = [1, 2, 3, 4, 5];
- let ys = box [7, 9, 11];
+ let ys = [7, 9, 11];
let mut it = xs.iter().chain(ys.iter());
assert_eq!(it.idx(0).unwrap(), &1);
assert_eq!(it.idx(5).unwrap(), &7);
}
#[test]
- fn test_MinMaxResult() {
+ fn test_min_max_result() {
let r: MinMaxResult<int> = NoElements;
assert_eq!(r.into_option(), None)
pub mod tuple;
pub mod fmt;
-// FIXME: this module should not exist. Once owned allocations are no longer a
-// language type, this module can move outside to the owned allocation
-// crate.
-mod should_not_exist;
-
#[doc(hidden)]
mod core {
pub use failure;
}
}
- fn R(i: Rc<RefCell<int>>) -> R {
+ fn r(i: Rc<RefCell<int>>) -> R {
R {
i: i
}
let i = Rc::new(RefCell::new(0));
{
- let x = R(realclone(&i));
+ let x = r(realclone(&i));
let opt = Some(x);
let _y = opt.unwrap();
}
}
#[cfg(test)]
-pub mod ptr_tests {
+#[allow(deprecated, experimental)]
+pub mod test {
use super::*;
use prelude::*;
use libc;
use realstd::str;
use realstd::str::Str;
+ use realstd::vec::Vec;
+ use realstd::collections::Collection;
use slice::{ImmutableVector, MutableVector};
#[test]
assert_eq!(p.fst, 50);
assert_eq!(p.snd, 60);
- let v0 = box [32000u16, 32001u16, 32002u16];
- let mut v1 = box [0u16, 0u16, 0u16];
+ let v0 = vec![32000u16, 32001u16, 32002u16];
+ let mut v1 = vec![0u16, 0u16, 0u16];
copy_memory(v1.as_mut_ptr().offset(1),
v0.as_ptr().offset(1), 1);
- assert!((v1[0] == 0u16 && v1[1] == 32001u16 && v1[2] == 0u16));
+ assert!((*v1.get(0) == 0u16 &&
+ *v1.get(1) == 32001u16 &&
+ *v1.get(2) == 0u16));
copy_memory(v1.as_mut_ptr(),
v0.as_ptr().offset(2), 1);
- assert!((v1[0] == 32002u16 && v1[1] == 32001u16 &&
- v1[2] == 0u16));
+ assert!((*v1.get(0) == 32002u16 &&
+ *v1.get(1) == 32001u16 &&
+ *v1.get(2) == 0u16));
copy_memory(v1.as_mut_ptr().offset(2),
v0.as_ptr(), 1u);
- assert!((v1[0] == 32002u16 && v1[1] == 32001u16 &&
- v1[2] == 32000u16));
+ assert!((*v1.get(0) == 32002u16 &&
+ *v1.get(1) == 32001u16 &&
+ *v1.get(2) == 32000u16));
}
}
"hello".with_c_str(|p0| {
"there".with_c_str(|p1| {
"thing".with_c_str(|p2| {
- let v = box [p0, p1, p2, null()];
+ let v = vec![p0, p1, p2, null()];
unsafe {
assert_eq!(buf_len(v.as_ptr()), 3u);
}
#[test]
fn test_ptr_addition() {
unsafe {
- let xs = box [5, ..16];
+ let xs = Vec::from_elem(16, 5);
let mut ptr = xs.as_ptr();
let end = ptr.offset(16);
ptr = ptr.offset(1);
}
- let mut xs_mut = xs.clone();
+ let mut xs_mut = xs;
let mut m_ptr = xs_mut.as_mut_ptr();
let m_end = m_ptr.offset(16);
m_ptr = m_ptr.offset(1);
}
- assert_eq!(xs_mut, box [10, ..16]);
+ assert!(xs_mut == Vec::from_elem(16, 10));
}
}
#[test]
fn test_ptr_subtraction() {
unsafe {
- let xs = box [0,1,2,3,4,5,6,7,8,9];
+ let xs = vec![0,1,2,3,4,5,6,7,8,9];
let mut idx = 9i8;
let ptr = xs.as_ptr();
idx = idx - 1i8;
}
- let mut xs_mut = xs.clone();
+ let mut xs_mut = xs;
let m_start = xs_mut.as_mut_ptr();
let mut m_ptr = m_start.offset(9);
m_ptr = m_ptr.offset(-1);
}
- assert_eq!(xs_mut, box [0,2,4,6,8,10,12,14,16,18]);
+ assert!(xs_mut == vec![0,2,4,6,8,10,12,14,16,18]);
}
}
let one = "oneOne".to_c_str();
let two = "twoTwo".to_c_str();
let three = "threeThree".to_c_str();
- let arr = box [
+ let arr = vec![
one.with_ref(|buf| buf),
two.with_ref(|buf| buf),
- three.with_ref(|buf| buf),
+ three.with_ref(|buf| buf)
];
let expected_arr = [
one, two, three
let one = "oneOne".to_c_str();
let two = "twoTwo".to_c_str();
let three = "threeThree".to_c_str();
- let arr = box [
+ let arr = vec![
one.with_ref(|buf| buf),
two.with_ref(|buf| buf),
three.with_ref(|buf| buf),
// fake a null terminator
- null(),
+ null()
];
let expected_arr = [
one, two, three
pub data: T,
}
-/// The representation of a Rust vector
-pub struct Vec<T> {
- pub fill: uint,
- pub alloc: uint,
- pub data: T,
-}
-
-/// The representation of a Rust string
-pub type String = Vec<u8>;
-
/// The representation of a Rust slice
pub struct Slice<T> {
pub data: *T,
impl<'a, T> Repr<Slice<T>> for &'a [T] {}
impl<'a> Repr<Slice<u8>> for &'a str {}
-impl<T> Repr<*Vec<T>> for ~[T] {}
#[cfg(test)]
mod tests {
}
}
- impl<T:PartialEq> PartialEq for ~[T] {
- #[inline]
- fn eq(&self, other: &~[T]) -> bool { self.as_slice() == *other }
- #[inline]
- fn ne(&self, other: &~[T]) -> bool { !self.eq(other) }
- }
-
impl<'a,T:Eq> Eq for &'a [T] {}
- impl<T:Eq> Eq for ~[T] {}
-
impl<'a,T:PartialEq, V: Vector<T>> Equiv<V> for &'a [T] {
#[inline]
fn equiv(&self, other: &V) -> bool { self.as_slice() == other.as_slice() }
}
- impl<'a,T:PartialEq, V: Vector<T>> Equiv<V> for ~[T] {
- #[inline]
- fn equiv(&self, other: &V) -> bool { self.as_slice() == other.as_slice() }
- }
-
impl<'a,T:Ord> Ord for &'a [T] {
fn cmp(&self, other: & &'a [T]) -> Ordering {
order::cmp(self.iter(), other.iter())
}
}
- impl<T: Ord> Ord for ~[T] {
- #[inline]
- fn cmp(&self, other: &~[T]) -> Ordering { self.as_slice().cmp(&other.as_slice()) }
- }
-
impl<'a, T: PartialOrd> PartialOrd for &'a [T] {
fn lt(&self, other: & &'a [T]) -> bool {
order::lt(self.iter(), other.iter())
order::gt(self.iter(), other.iter())
}
}
-
- impl<T: PartialOrd> PartialOrd for ~[T] {
- #[inline]
- fn lt(&self, other: &~[T]) -> bool { self.as_slice() < other.as_slice() }
- #[inline]
- fn le(&self, other: &~[T]) -> bool { self.as_slice() <= other.as_slice() }
- #[inline]
- fn ge(&self, other: &~[T]) -> bool { self.as_slice() >= other.as_slice() }
- #[inline]
- fn gt(&self, other: &~[T]) -> bool { self.as_slice() > other.as_slice() }
- }
}
#[cfg(test)]
fn as_slice<'a>(&'a self) -> &'a [T] { *self }
}
-impl<T> Vector<T> for ~[T] {
- #[inline(always)]
- fn as_slice<'a>(&'a self) -> &'a [T] { let v: &'a [T] = *self; v }
-}
-
impl<'a, T> Collection for &'a [T] {
/// Returns the length of a vector
#[inline]
}
}
-impl<T> Collection for ~[T] {
- /// Returns the length of a vector
- #[inline]
- fn len(&self) -> uint {
- self.as_slice().len()
- }
-}
-
/// Extension methods for vectors
pub trait ImmutableVector<'a, T> {
/**
/// # Example
///
/// ```rust
- /// let mut v = ~["foo".to_string(), "bar".to_string(), "baz".to_string()];
+ /// let mut v = ["foo".to_string(), "bar".to_string(), "baz".to_string()];
///
/// unsafe {
/// // `"baz".to_string()` is deallocated.
impl<'a, T> Default for &'a [T] {
fn default() -> &'a [T] { &[] }
}
-
-impl<T> Default for ~[T] {
- fn default() -> ~[T] { ~[] }
-}
true
}
+ #[cfg(stage0)]
fn visit_estr_box(&mut self) -> bool {
true
}
+ #[cfg(stage0)]
fn visit_estr_uniq(&mut self) -> bool {
- self.align_to::<~str>();
- if ! self.inner.visit_estr_uniq() { return false; }
- self.bump_past::<~str>();
- true
+ false
}
fn visit_estr_slice(&mut self) -> bool {
true
}
+ #[cfg(stage0)]
fn visit_evec_box(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool {
true
}
- fn visit_evec_uniq(&mut self, mtbl: uint, inner: *TyDesc) -> bool {
- self.align_to::<~[u8]>();
- if ! self.inner.visit_evec_uniq(mtbl, inner) { return false; }
- self.bump_past::<~[u8]>();
- true
+ #[cfg(stage0)]
+ fn visit_evec_uniq(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool {
+ false
}
fn visit_evec_slice(&mut self, mtbl: uint, inner: *TyDesc) -> bool {
true
}
- pub fn write_unboxed_vec_repr(&mut self, _: uint, v: &raw::Vec<()>, inner: *TyDesc) -> bool {
- self.write_vec_range(&v.data, v.fill, inner)
- }
-
fn write_escaped_char(&mut self, ch: char, is_str: bool) -> bool {
try!(self, match ch {
'\t' => self.writer.write("\\t".as_bytes()),
})
}
+ #[cfg(stage0)]
fn visit_estr_box(&mut self) -> bool {
- true
+ false
}
+ #[cfg(stage0)]
fn visit_estr_uniq(&mut self) -> bool {
- self.get::<~str>(|this, s| {
- try!(this, this.writer.write(['~' as u8]));
- this.write_escaped_slice(*s)
- })
+ false
}
fn visit_estr_slice(&mut self) -> bool {
})
}
- fn visit_evec_box(&mut self, mtbl: uint, inner: *TyDesc) -> bool {
- self.get::<&raw::Box<raw::Vec<()>>>(|this, b| {
- try!(this, this.writer.write(['@' as u8]));
- this.write_mut_qualifier(mtbl);
- this.write_unboxed_vec_repr(mtbl, &b.data, inner)
- })
+ #[cfg(stage0)]
+ fn visit_evec_box(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool {
+ true
}
- fn visit_evec_uniq(&mut self, mtbl: uint, inner: *TyDesc) -> bool {
- self.get::<&raw::Vec<()>>(|this, b| {
- try!(this, this.writer.write("box ".as_bytes()));
- this.write_unboxed_vec_repr(mtbl, *b, inner)
- })
+ #[cfg(stage0)]
+ fn visit_evec_uniq(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool {
+ true
}
fn visit_evec_slice(&mut self, mtbl: uint, inner: *TyDesc) -> bool {
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/")]
#![feature(phase)]
-#![deny(deprecated_owned_vector)]
#[cfg(test, stage0)] #[phase(syntax, link)] extern crate log;
#[cfg(test, not(stage0))] #[phase(plugin, link)] extern crate log;
use std::rand::Rng;
#[test]
- #[allow(deprecated_owned_vector)]
fn test_flate_round_trip() {
let mut r = rand::task_rng();
let mut words = vec!();
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/")]
-#![deny(deprecated_owned_vector)]
#![feature(plugin_registrar, managed_boxes)]
extern crate syntax;
html_playground_url = "http://play.rust-lang.org/")]
#![feature(globs, phase)]
#![deny(missing_doc)]
-#![deny(deprecated_owned_vector)]
#[cfg(test)] extern crate debug;
#[cfg(test, stage0)] #[phase(syntax, link)] extern crate log;
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/",
html_playground_url = "http://play.rust-lang.org/")]
-#![deny(deprecated_owned_vector)]
use std::cell::Cell;
use std::{cmp, os, path};
// of the contents of `Vec<T>`, since we anticipate that to be a
// frequent way to dynamically construct a vector.
-/// MaybeOwnedVector<'a,T> abstracts over `Vec<T>`, `~[T]`, `&'a [T]`.
+/// MaybeOwnedVector<'a,T> abstracts over `Vec<T>`, `&'a [T]`.
///
/// Some clients will have a pre-allocated vector ready to hand off in
/// a slice; others will want to create the set on the fly and hand
-/// off ownership, via either `Growable` or `FixedLen` depending on
-/// which kind of vector they have constructed. (The `FixedLen`
-/// variant is provided for interoperability with `std::slice` methods
-/// that return `~[T]`.)
+/// off ownership, via `Growable`.
pub enum MaybeOwnedVector<'a,T> {
Growable(Vec<T>),
- FixedLen(~[T]),
Borrowed(&'a [T]),
}
fn into_maybe_owned(self) -> MaybeOwnedVector<'a,T> { Growable(self) }
}
-impl<'a,T> IntoMaybeOwnedVector<'a,T> for ~[T] {
- #[inline]
- fn into_maybe_owned(self) -> MaybeOwnedVector<'a,T> { FixedLen(self) }
-}
-
impl<'a,T> IntoMaybeOwnedVector<'a,T> for &'a [T] {
#[inline]
fn into_maybe_owned(self) -> MaybeOwnedVector<'a,T> { Borrowed(self) }
pub fn iter(&'a self) -> slice::Items<'a,T> {
match self {
&Growable(ref v) => v.iter(),
- &FixedLen(ref v) => v.iter(),
&Borrowed(ref v) => v.iter(),
}
}
fn as_slice<'a>(&'a self) -> &'a [T] {
match self {
&Growable(ref v) => v.as_slice(),
- &FixedLen(ref v) => v.as_slice(),
&Borrowed(ref v) => v.as_slice(),
}
}
impl<'a,T:Clone> CloneableVector<T> for MaybeOwnedVector<'a,T> {
/// Returns a copy of `self`.
- fn to_owned(&self) -> ~[T] {
+ fn to_owned(&self) -> Vec<T> {
self.as_slice().to_owned()
}
/// Convert `self` into an owned slice, not making a copy if possible.
- fn into_owned(self) -> ~[T] {
+ fn into_owned(self) -> Vec<T> {
match self {
Growable(v) => v.as_slice().to_owned(),
- FixedLen(v) => v,
Borrowed(v) => v.to_owned(),
}
}
pub fn into_vec(self) -> Vec<T> {
match self {
Growable(v) => v,
- FixedLen(v) => Vec::from_slice(v.as_slice()),
Borrowed(v) => Vec::from_slice(v),
}
}
type Registers = [uint, ..22];
#[cfg(windows, target_arch = "x86_64")]
-fn new_regs() -> Box<Registers> { box [0, .. 34] }
+fn new_regs() -> Box<Registers> { box() ([0, .. 34]) }
#[cfg(not(windows), target_arch = "x86_64")]
-fn new_regs() -> Box<Registers> { box {let v = [0, .. 22]; v} }
+fn new_regs() -> Box<Registers> { box() ([0, .. 22]) }
#[cfg(target_arch = "x86_64")]
fn initialize_call_frame(regs: &mut Registers, fptr: InitFn, arg: uint,
// NB this does *not* include globs, please keep it that way.
#![feature(macro_rules, phase)]
#![allow(visible_private_types)]
-#![deny(deprecated_owned_vector)]
#[cfg(test)] #[phase(plugin, link)] extern crate log;
#[cfg(test)] extern crate rustuv;
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/")]
-
-#![deny(deprecated_owned_vector)]
#![feature(plugin_registrar, managed_boxes)]
extern crate syntax;
html_playground_url = "http://play.rust-lang.org/")]
#![feature(macro_rules)]
-#![deny(missing_doc, deprecated_owned_vector)]
+#![deny(missing_doc)]
use std::fmt;
use std::io::LineBufferedWriter;
html_root_url = "http://doc.rust-lang.org/",
html_playground_url = "http://play.rust-lang.org/")]
-#![deny(deprecated_owned_vector)]
-
extern crate rand;
pub use bigint::{BigInt, BigUint};
html_playground_url = "http://play.rust-lang.org/")]
#![feature(macro_rules, phase)]
-#![deny(missing_doc, deprecated_owned_vector)]
+#![deny(missing_doc)]
#[cfg(test)]
extern crate stdtest = "test";
LTO,
AST_JSON,
AST_JSON_NOEXPAND,
- LS
+ LS,
+ SAVE_ANALYSIS
]
0
)
("lto", "Perform LLVM link-time optimizations", LTO),
("ast-json", "Print the AST as JSON and halt", AST_JSON),
("ast-json-noexpand", "Print the pre-expansion AST as JSON and halt", AST_JSON_NOEXPAND),
- ("ls", "List the symbols defined by a library crate", LS))
+ ("ls", "List the symbols defined by a library crate", LS),
+ ("save-analysis", "Write syntax and type analysis information \
+ in addition to normal output", SAVE_ANALYSIS))
}
/// Declare a macro that will define all CodegenOptions fields and parsers all
if stop_after_phase_2(&sess) { return; }
let analysis = phase_3_run_analysis_passes(sess, &expanded_crate, ast_map);
+ phase_save_analysis(&analysis.ty_cx.sess, &expanded_crate, &analysis, outdir);
if stop_after_phase_3(&analysis.ty_cx.sess) { return; }
let (tcx, trans) = phase_4_translate_to_llvm(expanded_crate,
analysis, &outputs);
}
}
+pub fn phase_save_analysis(sess: &Session,
+ krate: &ast::Crate,
+ analysis: &CrateAnalysis,
+ odir: &Option<Path>) {
+ if (sess.opts.debugging_opts & config::SAVE_ANALYSIS) == 0 {
+ return;
+ }
+ time(sess.time_passes(), "save analysis", krate, |krate|
+ middle::save::process_crate(sess, krate, analysis, odir));
+}
+
pub struct CrateTranslation {
pub context: ContextRef,
pub module: ModuleRef,
pub fn main_args(args: &[String]) -> int {
let owned_args = args.to_owned();
- monitor(proc() run_compiler(owned_args));
+ monitor(proc() run_compiler(owned_args.as_slice()));
0
}
use std::os;
use std::cell::{Cell, RefCell};
+
pub struct Session {
pub targ_cfg: config::Config,
pub opts: config::Options,
pub mod expr_use_visitor;
pub mod dependency_format;
pub mod weak_lang_items;
+ pub mod save;
}
pub mod front {
pub fn LLVMRustDestroyArchive(AR: ArchiveRef);
pub fn LLVMRustSetDLLExportStorageClass(V: ValueRef);
+ pub fn LLVMVersionMajor() -> c_int;
pub fn LLVMVersionMinor() -> c_int;
pub fn LLVMRustGetSectionName(SI: SectionIteratorRef,
self.walk_expr(&*cond, in_out, loop_scopes);
let mut then_bits = in_out.to_owned();
- self.walk_block(&*then, then_bits, loop_scopes);
+ self.walk_block(&*then, then_bits.as_mut_slice(), loop_scopes);
self.walk_opt_expr(els, in_out, loop_scopes);
- join_bits(&self.dfcx.oper, then_bits, in_out);
+ join_bits(&self.dfcx.oper, then_bits.as_slice(), in_out);
}
ast::ExprWhile(cond, blk) => {
loop_id: expr.id,
break_bits: Vec::from_slice(in_out)
});
- self.walk_block(&*blk, body_bits, loop_scopes);
- self.add_to_entry_set(expr.id, body_bits);
+ self.walk_block(&*blk, body_bits.as_mut_slice(), loop_scopes);
+ self.add_to_entry_set(expr.id, body_bits.as_slice());
let new_loop_scope = loop_scopes.pop().unwrap();
copy_bits(new_loop_scope.break_bits.as_slice(), in_out);
}
loop_id: expr.id,
break_bits: Vec::from_slice(in_out)
});
- self.walk_block(&**blk, body_bits, loop_scopes);
- self.add_to_entry_set(expr.id, body_bits);
+ self.walk_block(&**blk, body_bits.as_mut_slice(), loop_scopes);
+ self.add_to_entry_set(expr.id, body_bits.as_slice());
let new_loop_scope = loop_scopes.pop().unwrap();
assert_eq!(new_loop_scope.loop_id, expr.id);
for arm in arms.iter() {
// in_out reflects the discr and all guards to date
- self.walk_opt_expr(arm.guard, guards, loop_scopes);
+ self.walk_opt_expr(arm.guard, guards.as_mut_slice(),
+ loop_scopes);
// determine the bits for the body and then union
// them into `in_out`, which reflects all bodies to date
let mut body = guards.to_owned();
self.walk_pat_alternatives(arm.pats.as_slice(),
- body,
+ body.as_mut_slice(),
loop_scopes);
- self.walk_expr(&*arm.body, body, loop_scopes);
- join_bits(&self.dfcx.oper, body, in_out);
+ self.walk_expr(&*arm.body, body.as_mut_slice(), loop_scopes);
+ join_bits(&self.dfcx.oper, body.as_slice(), in_out);
}
}
self.walk_expr(&**l, in_out, loop_scopes);
let temp = in_out.to_owned();
self.walk_expr(&**r, in_out, loop_scopes);
- join_bits(&self.dfcx.oper, temp, in_out);
+ join_bits(&self.dfcx.oper, temp.as_slice(), in_out);
}
ast::ExprIndex(l, r) |
let initial_state = in_out.to_owned();
for &pat in pats.iter() {
let mut temp = initial_state.clone();
- self.walk_pat(pat, temp, loop_scopes);
- join_bits(&self.dfcx.oper, temp, in_out);
+ self.walk_pat(pat, temp.as_mut_slice(), loop_scopes);
+ join_bits(&self.dfcx.oper, temp.as_slice(), in_out);
}
}
UnusedMustUse,
UnusedResult,
- DeprecatedOwnedVector,
-
Warnings,
RawPointerDeriving,
default: Allow,
}),
- ("deprecated_owned_vector",
- LintSpec {
- lint: DeprecatedOwnedVector,
- desc: "use of a `~[T]` vector",
- default: Allow,
- }),
-
("raw_pointer_deriving",
LintSpec {
lint: RawPointerDeriving,
}
}
-fn check_deprecated_owned_vector(cx: &Context, e: &ast::Expr) {
- let t = ty::expr_ty(cx.tcx, e);
- match ty::get(t).sty {
- ty::ty_uniq(t) => match ty::get(t).sty {
- ty::ty_vec(_, None) => {
- cx.span_lint(DeprecatedOwnedVector, e.span,
- "use of deprecated `~[]` vector; replaced by `std::vec::Vec`")
- }
- _ => {}
- },
- _ => {}
- }
-}
-
fn check_item_non_camel_case_types(cx: &Context, it: &ast::Item) {
fn is_camel_case(ident: ast::Ident) -> bool {
let ident = token::get_ident(ident);
check_type_limits(self, e);
check_unused_casts(self, e);
- check_deprecated_owned_vector(self, e);
visit::walk_expr(self, e, ());
}
}
Some(declaration) => {
for argument in declaration.inputs.iter() {
+ let mut bindings_list = HashMap::new();
this.resolve_pattern(&*argument.pat,
ArgumentIrrefutableMode,
- None);
+ &mut bindings_list);
this.resolve_type(&*argument.ty);
}
// Resolve the pattern.
- self.resolve_pattern(&*local.pat, LocalIrrefutableMode, None);
+ let mut bindings_list = HashMap::new();
+ self.resolve_pattern(&*local.pat,
+ LocalIrrefutableMode,
+ &mut bindings_list);
}
// build a map from pattern identifiers to binding-info's.
let mut bindings_list = HashMap::new();
for pattern in arm.pats.iter() {
- self.resolve_pattern(&**pattern,
- RefutableMode,
- Some(&mut bindings_list));
+ self.resolve_pattern(&**pattern, RefutableMode, &mut bindings_list);
}
// This has to happen *after* we determine which
mode: PatternBindingMode,
// Maps idents to the node ID for the (outermost)
// pattern that binds them
- mut bindings_list: Option<&mut HashMap<Name,NodeId>>) {
+ bindings_list: &mut HashMap<Name,NodeId>) {
let pat_id = pattern.id;
walk_pat(pattern, |pattern| {
match pattern.node {
// because that breaks the assumptions later
// passes make about or-patterns.)
- match bindings_list {
- Some(ref mut bindings_list)
- if !bindings_list.contains_key(&renamed) => {
- let this = &mut *self;
- let value_ribs = this.value_ribs.borrow();
- let length = value_ribs.len();
- let last_rib = value_ribs.get(
- length - 1);
- last_rib.bindings.borrow_mut()
- .insert(renamed, DlDef(def));
- bindings_list.insert(renamed, pat_id);
- }
- Some(ref mut b) => {
- if b.find(&renamed) == Some(&pat_id) {
- // Then this is a duplicate variable
- // in the same disjunct, which is an
- // error
- self.resolve_error(pattern.span,
- format!("identifier `{}` is bound \
- more than once in the same \
- pattern",
- path_to_str(path)).as_slice());
- }
- // Not bound in the same pattern: do nothing
- }
- None => {
- let this = &mut *self;
- {
- let value_ribs = this.value_ribs.borrow();
- let length = value_ribs.len();
- let last_rib = value_ribs.get(
- length - 1);
- last_rib.bindings.borrow_mut()
- .insert(renamed, DlDef(def));
- }
- }
+ if !bindings_list.contains_key(&renamed) {
+ let this = &mut *self;
+ let value_ribs = this.value_ribs.borrow();
+ let length = value_ribs.len();
+ let last_rib = value_ribs.get(
+ length - 1);
+ last_rib.bindings.borrow_mut()
+ .insert(renamed, DlDef(def));
+ bindings_list.insert(renamed, pat_id);
+ } else if bindings_list.find(&renamed) ==
+ Some(&pat_id) {
+ // Then this is a duplicate variable in the
+ // same disjunction, which is an error.
+ self.resolve_error(pattern.span,
+ format!("identifier `{}` is bound \
+ more than once in the same \
+ pattern",
+ path_to_str(path)).as_slice());
}
+ // Else, not bound in the same pattern: do
+ // nothing.
}
}
--- /dev/null
+// 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::gc::Gc;
+use std::io;
+use std::io::File;
+use std::io::fs;
+use std::os;
+
+use syntax::ast;
+use syntax::ast_util;
+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};
+use syntax::visit;
+use syntax::visit::Visitor;
+use syntax::print::pprust::{path_to_str,ty_to_str};
+
+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 {
+ span.expn_info.is_some() || span == DUMMY_SP
+}
+
+struct DxrVisitor<'l> {
+ sess: &'l Session,
+ analysis: &'l CrateAnalysis,
+
+ collected_paths: Vec<(NodeId, ast::Path, bool, recorder::Row)>,
+ collecting: bool,
+
+ span: SpanUtils<'l>,
+ fmt: FmtStrs<'l>,
+}
+
+impl <'l> DxrVisitor<'l> {
+ 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:",
+ path_to_str(path), spans.len(), path.segments.len());
+ 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};
+ let qualname = path_to_str(&sub_path);
+ result.push((*span, qualname));
+ segs = sub_path.segments;
+ }
+
+ result
+ }
+
+ fn write_sub_paths(&mut self, path: &ast::Path, scope_id: NodeId) {
+ 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(),
+ scope_id);
+ }
+ }
+
+ // As write_sub_paths, but does not process the last ident in the path (assuming it
+ // will be processed elsewhere).
+ fn write_sub_paths_truncated(&mut self, path: &ast::Path, scope_id: NodeId) {
+ 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(),
+ scope_id);
+ }
+ }
+
+ // As write_sub_paths, but expects a path of the form module_path::trait::method
+ // Where trait could actually be a struct too.
+ fn write_sub_path_trait_truncated(&mut self, path: &ast::Path, scope_id: NodeId) {
+ 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;
+ }
+ let sub_paths = sub_paths.slice(0, len-2);
+ for &(ref span, ref qualname) in sub_paths.iter() {
+ self.fmt.sub_mod_ref_str(path.span,
+ *span,
+ qualname.as_slice(),
+ scope_id);
+ }
+ }
+
+ // 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());
+ }
+ let def = *self.analysis.ty_cx.def_map.borrow().get(&ref_id);
+ 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());
+ }
+ let def = *def_map.get(&ref_id);
+ match def {
+ def::DefMod(_) |
+ def::DefForeignMod(_) => Some(recorder::ModRef),
+ def::DefStruct(_) => Some(recorder::StructRef),
+ def::DefTy(_) |
+ def::DefTrait(_) => Some(recorder::TypeRef),
+ def::DefStatic(_, _) |
+ def::DefBinding(_, _) |
+ def::DefArg(_, _) |
+ def::DefLocal(_, _) |
+ def::DefVariant(_, _, _) |
+ def::DefUpvar(_, _, _, _) => Some(recorder::VarRef),
+
+ def::DefFn(_, _) => Some(recorder::FnRef),
+
+ def::DefSelfTy(_) |
+ def::DefRegion(_) |
+ def::DefTyParamBinder(_) |
+ def::DefLabel(_) |
+ def::DefStaticMethod(_, _, _) |
+ def::DefTyParam(_, _) |
+ def::DefUse(_) |
+ def::DefMethod(_, _) |
+ def::DefPrimTy(_) => {
+ self.sess.span_bug(span, format!("lookup_def_kind for unexpected item: {:?}",
+ def).as_slice());
+ },
+ }
+ }
+
+ fn process_formals(&mut self, formals: &Vec<ast::Arg>, qualname: &str, e:DxrVisitorEnv) {
+ for arg in formals.iter() {
+ assert!(self.collected_paths.len() == 0 && !self.collecting);
+ self.collecting = true;
+ self.visit_pat(&*arg.pat, e);
+ self.collecting = false;
+ let span_utils = self.span;
+ for &(id, ref p, _, _) in self.collected_paths.iter() {
+ let typ = ppaux::ty_to_str(&self.analysis.ty_cx,
+ *self.analysis.ty_cx.node_types.borrow().get(&(id as uint)));
+ // 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,
+ path_to_str(p).as_slice(),
+ typ.as_slice());
+ }
+ self.collected_paths.clear();
+ }
+ }
+
+ fn process_method(&mut self, method: &ast::Method, e:DxrVisitorEnv) {
+ 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 {
+ ast::ItemImpl(_, _, ty, _) => {
+ let mut result = String::from_str("<");
+ result.push_str(ty_to_str(&*ty).as_slice());
+
+ match ty::trait_of_method(&self.analysis.ty_cx,
+ ast_util::local_def(method.id)) {
+ Some(def_id) => {
+ result.push_str(" as ");
+ result.push_str(
+ ty::item_path_str(&self.analysis.ty_cx, def_id).as_slice());
+ },
+ None => {}
+ }
+ result.append(">::")
+ }
+ _ => {
+ 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,
+ format!("Container {} for method {} is not a node item {:?}",
+ impl_id.node,
+ method.id,
+ self.analysis.ty_cx.map.get(impl_id.node)
+ ).as_slice());
+ },
+ },
+ None => match ty::trait_of_method(&self.analysis.ty_cx,
+ ast_util::local_def(method.id)) {
+ Some(def_id) => {
+ scope_id = def_id.node;
+ match self.analysis.ty_cx.map.get(def_id.node) {
+ NodeItem(_) => {
+ let result = ty::item_path_str(&self.analysis.ty_cx, def_id);
+ result.append("::")
+ }
+ _ => {
+ 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());
+ },
+ },
+ };
+
+ qualname.push_str(get_ident(method.ident).get());
+ let qualname = qualname.as_slice();
+
+ // record the decl for this def (if it has one)
+ let decl_id = ty::trait_method_of_method(&self.analysis.ty_cx,
+ ast_util::local_def(method.id))
+ .filtered(|def_id| method.id != 0 && def_id.node == 0);
+
+ 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);
+
+ self.process_formals(&method.decl.inputs, qualname, e);
+
+ // walk arg and return types
+ for arg in method.decl.inputs.iter() {
+ self.visit_ty(&*arg.ty, e);
+ }
+ self.visit_ty(&*method.decl.output, e);
+ // walk the fn body
+ self.visit_block(&*method.body, DxrVisitorEnv::new_nested(method.id));
+
+ self.process_generic_params(&method.generics,
+ method.span,
+ qualname,
+ method.id,
+ e);
+ }
+
+ fn process_trait_ref(&mut self,
+ trait_ref: &ast::TraitRef,
+ e: DxrVisitorEnv,
+ 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,
+ e.cur_scope);
+ match impl_id {
+ Some(impl_id) => self.fmt.impl_str(trait_ref.path.span,
+ sub_span,
+ impl_id,
+ id,
+ e.cur_scope),
+ None => (),
+ }
+ visit::walk_path(self, &trait_ref.path, e);
+ },
+ 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);
+ let typ = ppaux::ty_to_str(&self.analysis.ty_cx,
+ *self.analysis.ty_cx.node_types.borrow().get(&(field.node.id as uint)));
+ match self.span.sub_span_before_token(field.span, token::COLON) {
+ 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,
+ id: NodeId,
+ e: DxrVisitorEnv) {
+ // 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(),
+ "");
+ }
+ self.visit_generics(generics, e);
+ }
+
+ fn process_fn(&mut self,
+ item: &ast::Item,
+ e: DxrVisitorEnv,
+ decl: ast::P<ast::FnDecl>,
+ ty_params: &ast::Generics,
+ body: ast::P<ast::Block>) {
+ let qualname = self.analysis.ty_cx.map.path_to_str(item.id);
+
+ 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(),
+ e.cur_scope);
+
+ self.process_formals(&decl.inputs, qualname.as_slice(), e);
+
+ // walk arg and return types
+ for arg in decl.inputs.iter() {
+ self.visit_ty(&*arg.ty, e);
+ }
+ self.visit_ty(&*decl.output, e);
+
+ // walk the body
+ self.visit_block(&*body, DxrVisitorEnv::new_nested(item.id));
+
+ self.process_generic_params(ty_params, item.span, qualname.as_slice(), item.id, e);
+ }
+
+ fn process_static(&mut self,
+ item: &ast::Item,
+ e: DxrVisitorEnv,
+ typ: ast::P<ast::Ty>,
+ mt: ast::Mutability,
+ expr: &ast::Expr)
+ {
+ let qualname = self.analysis.ty_cx.map.path_to_str(item.id);
+
+ // If the variable is immutable, save the initialising expresion.
+ 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(),
+ ty_to_str(&*typ).as_slice(),
+ e.cur_scope);
+
+ // walk type and init value
+ self.visit_ty(&*typ, e);
+ self.visit_expr(expr, e);
+ }
+
+ fn process_struct(&mut self,
+ item: &ast::Item,
+ e: DxrVisitorEnv,
+ def: &ast::StructDef,
+ ty_params: &ast::Generics) {
+ let qualname = self.analysis.ty_cx.map.path_to_str(item.id);
+
+ 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(),
+ e.cur_scope);
+
+ // fields
+ for field in def.fields.iter() {
+ self.process_struct_field_def(field, qualname.as_slice(), item.id);
+ self.visit_ty(&*field.node.ty, e);
+ }
+
+ self.process_generic_params(ty_params, item.span, qualname.as_slice(), item.id, e);
+ }
+
+ fn process_enum(&mut self,
+ item: &ast::Item,
+ e: DxrVisitorEnv,
+ enum_definition: &ast::EnumDef,
+ ty_params: &ast::Generics) {
+ let qualname = self.analysis.ty_cx.map.path_to_str(item.id);
+ 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(),
+ e.cur_scope),
+ 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();
+ let qualname = qualname.clone().append("::").append(name);
+ 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() {
+ self.visit_ty(&*arg.ty, e);
+ }
+ }
+ 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);
+ self.visit_ty(&*field.node.ty, e);
+ }
+ }
+ }
+ }
+
+ self.process_generic_params(ty_params, item.span, qualname.as_slice(), item.id, e);
+ }
+
+ fn process_impl(&mut self,
+ item: &ast::Item,
+ e: DxrVisitorEnv,
+ type_parameters: &ast::Generics,
+ trait_ref: &Option<ast::TraitRef>,
+ typ: ast::P<ast::Ty>,
+ methods: &Vec<Gc<ast::Method>>) {
+ 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,
+ e.cur_scope);
+ self.fmt.impl_str(path.span,
+ sub_span,
+ item.id,
+ id,
+ e.cur_scope);
+ },
+ None => ()
+ }
+ },
+ _ => self.visit_ty(&*typ, e),
+ }
+
+ match *trait_ref {
+ Some(ref trait_ref) => self.process_trait_ref(trait_ref, e, Some(item.id)),
+ None => (),
+ }
+
+ self.process_generic_params(type_parameters, item.span, "", item.id, e);
+ for method in methods.iter() {
+ visit::walk_method_helper(self, &**method, e)
+ }
+ }
+
+ fn process_trait(&mut self,
+ item: &ast::Item,
+ e: DxrVisitorEnv,
+ generics: &ast::Generics,
+ trait_refs: &Vec<ast::TraitRef>,
+ methods: &Vec<ast::TraitMethod>) {
+ let qualname = self.analysis.ty_cx.map.path_to_str(item.id);
+
+ 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(),
+ e.cur_scope);
+
+ // super-traits
+ for trait_ref in trait_refs.iter() {
+ 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,
+ e.cur_scope);
+ self.fmt.inherit_str(trait_ref.path.span,
+ sub_span,
+ id,
+ item.id);
+ },
+ None => ()
+ }
+ }
+
+ // walk generics and methods
+ self.process_generic_params(generics, item.span, qualname.as_slice(), item.id, e);
+ for method in methods.iter() {
+ self.visit_trait_method(method, e)
+ }
+ }
+
+ fn process_mod(&mut self,
+ item: &ast::Item, // The module in question, represented as an item.
+ e: DxrVisitorEnv,
+ m: &ast::Mod) {
+ let qualname = self.analysis.ty_cx.map.path_to_str(item.id);
+
+ 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(),
+ e.cur_scope,
+ filename.as_slice());
+
+ visit::walk_mod(self, m, DxrVisitorEnv::new_nested(item.id));
+ }
+
+ fn process_path(&mut self,
+ ex: &ast::Expr,
+ e: DxrVisitorEnv,
+ 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());
+ }
+ let def = def_map.get(&ex.id);
+ let sub_span = self.span.span_for_last_ident(ex.span);
+ match *def {
+ def::DefLocal(id, _) |
+ def::DefArg(id, _) |
+ def::DefUpvar(id, _, _, _) |
+ def::DefBinding(id, _) => self.fmt.ref_str(recorder::VarRef,
+ ex.span,
+ sub_span,
+ ast_util::local_def(id),
+ e.cur_scope),
+ def::DefStatic(def_id,_) |
+ def::DefVariant(_, def_id, _) => self.fmt.ref_str(recorder::VarRef,
+ ex.span,
+ sub_span,
+ def_id,
+ e.cur_scope),
+ def::DefStruct(def_id) => self.fmt.ref_str(recorder::StructRef,
+ ex.span,
+ sub_span,
+ def_id,
+ e.cur_scope),
+ def::DefStaticMethod(declid, provenence, _) => {
+ let sub_span = self.span.sub_span_for_meth_name(ex.span);
+ let defid = if declid.krate == ast::LOCAL_CRATE {
+ let m = ty::method(&self.analysis.ty_cx, declid);
+ match provenence {
+ def::FromTrait(def_id) =>
+ Some(ty::trait_methods(&self.analysis.ty_cx, def_id)
+ .iter().find(|mr| mr.ident.name == m.ident.name).unwrap().def_id),
+ def::FromImpl(def_id) => {
+ let impl_methods = self.analysis.ty_cx.impl_methods.borrow();
+ Some(*impl_methods.get(&def_id)
+ .iter().find(|mr|
+ ty::method(
+ &self.analysis.ty_cx, **mr).ident.name == m.ident.name)
+ .unwrap())
+ }
+ }
+ } else {
+ None
+ };
+ self.fmt.meth_call_str(ex.span,
+ sub_span,
+ defid,
+ Some(declid),
+ e.cur_scope);
+ },
+ def::DefFn(def_id, _) => self.fmt.fn_call_str(ex.span,
+ sub_span,
+ def_id,
+ e.cur_scope),
+ _ => 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 {
+ def::DefStaticMethod(_, _, _) => {
+ self.write_sub_path_trait_truncated(path, e.cur_scope);
+ },
+ def::DefLocal(_, _) |
+ def::DefArg(_, _) |
+ def::DefStatic(_,_) |
+ def::DefStruct(_) |
+ def::DefFn(_, _) => self.write_sub_paths_truncated(path, e.cur_scope),
+ _ => {},
+ }
+
+ visit::walk_path(self, path, e);
+ }
+
+ fn process_struct_lit(&mut self,
+ ex: &ast::Expr,
+ e: DxrVisitorEnv,
+ path: &ast::Path,
+ fields: &Vec<ast::Field>,
+ base: Option<Gc<ast::Expr>>) {
+ 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,
+ e.cur_scope);
+ },
+ None => ()
+ }
+
+ self.write_sub_paths_truncated(path, e.cur_scope);
+
+ 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,
+ e.cur_scope);
+ }
+ }
+ }
+ None => {}
+ }
+
+ self.visit_expr(&*field.expr, e)
+ }
+ visit::walk_expr_opt(self, base, e)
+ }
+
+ fn process_method_call(&mut self,
+ ex: &ast::Expr,
+ e: DxrVisitorEnv,
+ args: &Vec<Gc<ast::Expr>>) {
+ let method_map = self.analysis.ty_cx.method_map.borrow();
+ let method_callee = method_map.get(&typeck::MethodCall::expr(ex.id));
+ let (def_id, decl_id) = match method_callee.origin {
+ typeck::MethodStatic(def_id) => {
+ // method invoked on an object with a concrete type (not a static method)
+ let decl_id = ty::trait_method_of_method(&self.analysis.ty_cx, def_id);
+
+ // This incantation is required if the method referenced is a trait's
+ // defailt implementation.
+ let def_id = ty::method(&self.analysis.ty_cx, def_id).provided_source
+ .unwrap_or(def_id);
+ (Some(def_id), decl_id)
+ }
+ typeck::MethodParam(mp) => {
+ // method invoked on a type parameter
+ let method = ty::trait_method(&self.analysis.ty_cx,
+ mp.trait_id,
+ mp.method_num);
+ (None, Some(method.def_id))
+ },
+ typeck::MethodObject(mo) => {
+ // method invoked on a trait instance
+ let method = ty::trait_method(&self.analysis.ty_cx,
+ mo.trait_id,
+ mo.method_num);
+ (None, Some(method.def_id))
+ },
+ };
+ 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,
+ e.cur_scope);
+
+ // walk receiver and args
+ visit::walk_exprs(self, args.as_slice(), e);
+ }
+
+ fn process_pat(&mut self, p:&ast::Pat, e: DxrVisitorEnv) {
+ 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));
+ visit::walk_path(self, path, e);
+ 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());
+ }
+ };
+ // The AST doesn't give us a span for the struct field, so we have
+ // to figure out where it is by assuming it's the token before each colon.
+ let field_spans = self.span.sub_spans_before_tokens(p.span,
+ token::COMMA,
+ token::COLON);
+ if fields.len() != field_spans.len() {
+ self.sess.span_bug(p.span,
+ format!("Mismatched field count in '{}', found {}, expected {}",
+ self.span.snippet(p.span), field_spans.len(), fields.len()
+ ).as_slice());
+ }
+ for (field, &span) in fields.iter().zip(field_spans.iter()) {
+ self.visit_pat(&*field.pat, e);
+ if span.is_none() {
+ continue;
+ }
+ 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,
+ span,
+ f.id,
+ e.cur_scope);
+ break;
+ }
+ }
+ }
+ }
+ ast::PatEnum(ref path, _) => {
+ self.collected_paths.push((p.id, path.clone(), false, recorder::VarRef));
+ visit::walk_pat(self, p, e);
+ }
+ ast::PatIdent(bm, ref path, ref optional_subpattern) => {
+ 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
+ self.collected_paths.push((p.id, path.clone(), immut, recorder::VarRef));
+ match *optional_subpattern {
+ None => {}
+ Some(subpattern) => self.visit_pat(&*subpattern, e),
+ }
+ }
+ _ => visit::walk_pat(self, p, e)
+ }
+ }
+}
+
+impl<'l> Visitor<DxrVisitorEnv> for DxrVisitor<'l> {
+ fn visit_item(&mut self, item:&ast::Item, e: DxrVisitorEnv) {
+ if generated_code(item.span) {
+ return
+ }
+
+ match item.node {
+ ast::ItemFn(decl, _, _, ref ty_params, body) =>
+ self.process_fn(item, e, decl, ty_params, body),
+ ast::ItemStatic(typ, mt, expr) =>
+ self.process_static(item, e, typ, mt, &*expr),
+ ast::ItemStruct(def, ref ty_params) => self.process_struct(item, e, &*def, ty_params),
+ ast::ItemEnum(ref def, ref ty_params) => self.process_enum(item, e, def, ty_params),
+ ast::ItemImpl(ref ty_params, ref trait_ref, typ, ref methods) =>
+ self.process_impl(item, e, ty_params, trait_ref, typ, methods),
+ ast::ItemTrait(ref generics, _, ref trait_refs, ref methods) =>
+ self.process_trait(item, e, generics, trait_refs, methods),
+ ast::ItemMod(ref m) => self.process_mod(item, e, m),
+ ast::ItemTy(ty, ref ty_params) => {
+ let qualname = self.analysis.ty_cx.map.path_to_str(item.id);
+ let value = ty_to_str(&*ty);
+ 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());
+
+ self.visit_ty(&*ty, e);
+ self.process_generic_params(ty_params, item.span, qualname.as_slice(), item.id, e);
+ },
+ ast::ItemMac(_) => (),
+ _ => visit::walk_item(self, item, e),
+ }
+ }
+
+ fn visit_generics(&mut self, generics: &ast::Generics, e: DxrVisitorEnv) {
+ for param in generics.ty_params.iter() {
+ for bound in param.bounds.iter() {
+ match *bound {
+ ast::TraitTyParamBound(ref trait_ref) => {
+ self.process_trait_ref(trait_ref, e, None);
+ }
+ _ => {}
+ }
+ }
+ match param.default {
+ Some(ty) => self.visit_ty(&*ty, e),
+ None => (),
+ }
+ }
+ }
+
+ // We don't actually index functions here, that is done in visit_item/ItemFn.
+ // Here we just visit methods.
+ fn visit_fn(&mut self,
+ fk: &visit::FnKind,
+ fd: &ast::FnDecl,
+ b: &ast::Block,
+ s: Span,
+ _: NodeId,
+ e: DxrVisitorEnv) {
+ if generated_code(s) {
+ return;
+ }
+
+ match *fk {
+ visit::FkMethod(_, _, method) => self.process_method(method, e),
+ _ => visit::walk_fn(self, fk, fd, b, s, e),
+ }
+ }
+
+ fn visit_trait_method(&mut self, tm: &ast::TraitMethod, e: DxrVisitorEnv) {
+ match *tm {
+ ast::Required(ref method_type) => {
+ if generated_code(method_type.span) {
+ return;
+ }
+
+ let mut scope_id ;
+ let mut qualname = match ty::trait_of_method(&self.analysis.ty_cx,
+ ast_util::local_def(method_type.id)) {
+ Some(def_id) => {
+ scope_id = def_id.node;
+ ty::item_path_str(&self.analysis.ty_cx, def_id).append("::")
+ },
+ 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() {
+ self.visit_ty(&*arg.ty, e);
+ }
+ self.visit_ty(&*method_type.decl.output, e);
+
+ self.process_generic_params(&method_type.generics,
+ method_type.span,
+ qualname,
+ method_type.id,
+ e);
+ }
+ ast::Provided(method) => self.process_method(&*method, e),
+ }
+ }
+
+ fn visit_view_item(&mut self, i:&ast::ViewItem, e:DxrVisitorEnv) {
+ 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,
+ e.cur_scope),
+ 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 =
+ match self.span.sub_span_before_token(path.span, token::EQ) {
+ 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(),
+ e.cur_scope);
+ self.write_sub_paths_truncated(path, e.cur_scope);
+ }
+ ast::ViewPathGlob(ref path, _) => {
+ self.write_sub_paths(path, e.cur_scope);
+ }
+ ast::ViewPathList(ref path, ref list, _) => {
+ for plid in list.iter() {
+ match self.lookup_type_ref(plid.node.id) {
+ Some(id) => match self.lookup_def_kind(plid.node.id, plid.span) {
+ Some(kind) => self.fmt.ref_str(kind,
+ plid.span,
+ Some(plid.span),
+ id,
+ e.cur_scope),
+ None => (),
+ },
+ None => ()
+ }
+ }
+
+ self.write_sub_paths(path, e.cur_scope);
+ }
+ }
+ },
+ ast::ViewItemExternCrate(ident, ref s, id) => {
+ let name = get_ident(ident).get().to_owned();
+ let s = match *s {
+ Some((ref s, _)) => s.get().to_owned(),
+ None => name.to_owned(),
+ };
+ 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,
+ name.as_slice(),
+ s.as_slice(),
+ e.cur_scope);
+ },
+ }
+ }
+
+ fn visit_ty(&mut self, t: &ast::Ty, e: DxrVisitorEnv) {
+ 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,
+ e.cur_scope);
+ },
+ None => ()
+ }
+
+ self.write_sub_paths_truncated(path, e.cur_scope);
+
+ visit::walk_path(self, path, e);
+ },
+ _ => visit::walk_ty(self, t, e),
+ }
+ }
+
+ fn visit_expr(&mut self, ex: &ast::Expr, e: DxrVisitorEnv) {
+ if generated_code(ex.span) {
+ return
+ }
+
+ match ex.node {
+ ast::ExprCall(_f, ref _args) => {
+ // Don't need to do anything for function calls,
+ // because just walking the callee path does what we want.
+ visit::walk_expr(self, ex, e);
+ },
+ ast::ExprPath(ref path) => self.process_path(ex, e, path),
+ ast::ExprStruct(ref path, ref fields, base) =>
+ self.process_struct_lit(ex, e, path, fields, base),
+ ast::ExprMethodCall(_, _, ref args) => self.process_method_call(ex, e, args),
+ ast::ExprField(sub_ex, ident, _) => {
+ if generated_code(sub_ex.span) {
+ return
+ }
+
+ self.visit_expr(&*sub_ex, e);
+
+ let t = ty::expr_ty_adjusted(&self.analysis.ty_cx, &*sub_ex);
+ 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() {
+ if f.name == ident.name {
+ let sub_span = self.span.span_for_last_ident(ex.span);
+ self.fmt.ref_str(recorder::VarRef,
+ ex.span,
+ sub_span,
+ f.id,
+ e.cur_scope);
+ break;
+ }
+ }
+ },
+ _ => self.sess.span_bug(ex.span,
+ "Expected struct type, but not ty_struct"),
+ }
+ },
+ ast::ExprFnBlock(decl, body) => {
+ if generated_code(body.span) {
+ return
+ }
+
+ let id = String::from_str("$").append(ex.id.to_str().as_slice());
+ self.process_formals(&decl.inputs, id.as_slice(), e);
+
+ // walk arg and return types
+ for arg in decl.inputs.iter() {
+ self.visit_ty(&*arg.ty, e);
+ }
+ self.visit_ty(&*decl.output, e);
+
+ // walk the body
+ self.visit_block(&*body, DxrVisitorEnv::new_nested(ex.id));
+ },
+ _ => {
+ visit::walk_expr(self, ex, e)
+ },
+ }
+ }
+
+ fn visit_mac(&mut self, _: &ast::Mac, _: DxrVisitorEnv) {
+ // Just stop, macros are poison to us.
+ }
+
+ fn visit_pat(&mut self, p: &ast::Pat, e: DxrVisitorEnv) {
+ self.process_pat(p, e);
+ if !self.collecting {
+ self.collected_paths.clear();
+ }
+ }
+
+ fn visit_arm(&mut self, arm: &ast::Arm, e: DxrVisitorEnv) {
+ assert!(self.collected_paths.len() == 0 && !self.collecting);
+ self.collecting = true;
+
+ for pattern in arm.pats.iter() {
+ // collect paths from the arm's patterns
+ self.visit_pat(&**pattern, e);
+ }
+ self.collecting = false;
+ // process collected paths
+ for &(id, ref p, ref immut, ref_kind) in self.collected_paths.iter() {
+ let value = if *immut {
+ self.span.snippet(p.span).into_owned()
+ } else {
+ "<mutable>".to_owned()
+ };
+ 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());
+ }
+ let def = def_map.get(&id);
+ match *def {
+ def::DefBinding(id, _) => self.fmt.variable_str(p.span,
+ sub_span,
+ id,
+ path_to_str(p).as_slice(),
+ value.as_slice(),
+ ""),
+ def::DefVariant(_,id,_) => self.fmt.ref_str(ref_kind,
+ p.span,
+ sub_span,
+ id,
+ e.cur_scope),
+ // FIXME(nrc) what is this doing here?
+ def::DefStatic(_, _) => {}
+ _ => error!("unexpected defintion kind when processing collected paths: {:?}", *def)
+ }
+ }
+ self.collected_paths.clear();
+ visit::walk_expr_opt(self, arm.guard, e);
+ self.visit_expr(&*arm.body, e);
+ }
+
+ fn visit_stmt(&mut self, s:&ast::Stmt, e:DxrVisitorEnv) {
+ if generated_code(s.span) {
+ return
+ }
+
+ visit::walk_stmt(self, s, e)
+ }
+
+ fn visit_local(&mut self, l:&ast::Local, e: DxrVisitorEnv) {
+ 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;
+ self.visit_pat(&*l.pat, e);
+ self.collecting = false;
+
+ let value = self.span.snippet(l.span);
+
+ for &(id, ref p, ref immut, _) in self.collected_paths.iter() {
+ let value = if *immut { value.to_owned() } else { "<mutable>".to_owned() };
+ let types = self.analysis.ty_cx.node_types.borrow();
+ let typ = ppaux::ty_to_str(&self.analysis.ty_cx, *types.get(&(id as uint)));
+ // 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,
+ path_to_str(p).as_slice(),
+ value.as_slice(),
+ typ.as_slice());
+ }
+ self.collected_paths.clear();
+
+ // Just walk the initialiser and type (don't want to walk the pattern again).
+ self.visit_ty(&*l.ty, e);
+ visit::walk_expr_opt(self, l.init, e);
+ }
+}
+
+#[deriving(Clone)]
+struct DxrVisitorEnv {
+ cur_scope: NodeId,
+}
+
+impl DxrVisitorEnv {
+ fn new() -> DxrVisitorEnv {
+ DxrVisitorEnv{cur_scope: 0}
+ }
+ fn new_nested(new_mod: NodeId) -> DxrVisitorEnv {
+ DxrVisitorEnv{cur_scope: new_mod}
+ }
+}
+
+pub fn process_crate(sess: &Session,
+ krate: &ast::Crate,
+ analysis: &CrateAnalysis,
+ odir: &Option<Path>) {
+ if generated_code(krate.span) {
+ return;
+ }
+
+ let (cratename, crateid) = match attr::find_crateid(krate.attrs.as_slice()) {
+ Some(crateid) => (crateid.name.clone(), crateid.to_str()),
+ None => {
+ info!("Could not find crate name, using 'unknown_crate'");
+ (String::from_str("unknown_crate"),"unknown_crate".to_owned())
+ },
+ };
+
+ info!("Dumping crate {} ({})", cratename, crateid);
+
+ // 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"),
+ },
+ };
+
+ match fs::mkdir_recursive(&root_path, io::UserRWX) {
+ 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);
+ }
+
+ // Create ouput file.
+ 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();
+
+ let mut visitor = DxrVisitor{ sess: sess,
+ analysis: analysis,
+ collected_paths: vec!(),
+ collecting: false,
+ fmt: FmtStrs::new(box Recorder {
+ out: output_file as Box<Writer>,
+ dump_spans: false,
+ },
+ SpanUtils {
+ sess: sess,
+ err_count: Cell::new(0)
+ },
+ cratename.clone()),
+ span: SpanUtils {
+ sess: sess,
+ err_count: Cell::new(0)
+ }};
+
+ visitor.dump_crate_info(cratename.as_slice(), krate);
+
+ visit::walk_crate(&mut visitor, krate, DxrVisitorEnv::new());
+}
--- /dev/null
+// 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.
+
+use middle::save::escape;
+use middle::save::span_utils::SpanUtils;
+
+use std::vec::Vec;
+
+use syntax::ast;
+use syntax::ast::{NodeId,DefId};
+use syntax::codemap::*;
+
+pub struct Recorder {
+ // output file
+ pub out: Box<Writer>,
+ pub dump_spans: bool,
+}
+
+impl Recorder {
+ pub fn record(&mut self, info: &str) {
+ match write!(self.out, "{}", info) {
+ Err(_) => error!("Error writing output '{}'", info),
+ _ => (),
+ }
+ }
+
+ pub fn dump_span(&mut self,
+ su: SpanUtils,
+ kind: &str,
+ span: Span,
+ _sub_span: Option<Span>) {
+ assert!(self.dump_spans);
+ let result = format!("span,kind,{},{},text,\"{}\"\n",
+ kind, su.extent_str(span), escape(su.snippet(span)));
+ self.record(result.as_slice());
+ }
+}
+
+pub struct FmtStrs<'a> {
+ pub recorder: Box<Recorder>,
+ span: SpanUtils<'a>,
+ krate: String,
+}
+
+macro_rules! s { ($e:expr) => { format!("{}", $e) }}
+macro_rules! svec {
+ ($($e:expr),*) => ({
+ // leading _ to allow empty construction without a warning.
+ let mut _temp = ::std::vec::Vec::new();
+ $(_temp.push(s!($e));)*
+ _temp
+ })
+}
+
+pub enum Row {
+ Variable,
+ Enum,
+ Variant,
+ VariantStruct,
+ Function,
+ MethodDecl,
+ Struct,
+ Trait,
+ Impl,
+ Module,
+ UseAlias,
+ ExternCrate,
+ Inheritance,
+ MethodCall,
+ Typedef,
+ ExternalCrate,
+ Crate,
+ FnCall,
+ ModRef,
+ VarRef,
+ TypeRef,
+ StructRef,
+ FnRef,
+}
+
+impl<'a> FmtStrs<'a> {
+ pub fn new(rec: Box<Recorder>, span: SpanUtils<'a>, krate: String) -> FmtStrs<'a> {
+ FmtStrs {
+ recorder: rec,
+ span: span,
+ krate: krate,
+ }
+ }
+
+ // A map from kind of item to a tuple of
+ // a string representation of the name
+ // a vector of field names
+ // whether this kind requires a span
+ // whether dump_spans should dump for this kind
+ fn lookup_row(r: Row) -> (&'static str, Vec<&'static str>, bool, bool) {
+ match r {
+ Variable => ("variable",
+ vec!("id","name","qualname","value","type","scopeid"),
+ true, true),
+ Enum => ("enum", vec!("id","qualname","scopeid"), true, true),
+ Variant => ("variant", vec!("id","name","qualname","value","scopeid"), true, true),
+ VariantStruct => ("variant_struct",
+ vec!("id","ctor_id","qualname","value","scopeid"), true, true),
+ Function => ("function", vec!("id","qualname","declid","declidcrate","scopeid"),
+ true, true),
+ MethodDecl => ("method_decl", vec!("id","qualname","scopeid"), true, true),
+ Struct => ("struct", vec!("id","ctor_id","qualname","scopeid"), true, true),
+ Trait => ("trait", vec!("id","qualname","scopeid"), true, true),
+ Impl => ("impl", vec!("id","refid","refidcrate","scopeid"), true, true),
+ Module => ("module", vec!("id","qualname","scopeid","def_file"), true, false),
+ UseAlias => ("use_alias",
+ vec!("id","refid","refidcrate","name","scopeid"),
+ true, true),
+ ExternCrate => ("extern_crate",
+ vec!("id","name","location","crate","scopeid"),
+ true, true),
+ Inheritance => ("inheritance",
+ vec!("base","basecrate","derived","derivedcrate"),
+ true, false),
+ MethodCall => ("method_call",
+ vec!("refid","refidcrate","declid","declidcrate","scopeid"),
+ true, true),
+ Typedef => ("typedef", vec!("id","qualname","value"), true, true),
+ ExternalCrate => ("external_crate", vec!("name","crate","file_name"), false, false),
+ Crate => ("crate", vec!("name"), true, false),
+ FnCall => ("fn_call", vec!("refid","refidcrate","qualname","scopeid"), true, true),
+ ModRef => ("mod_ref", vec!("refid","refidcrate","qualname","scopeid"), true, true),
+ VarRef => ("var_ref", vec!("refid","refidcrate","qualname","scopeid"), true, true),
+ TypeRef => ("type_ref",
+ vec!("refid","refidcrate","qualname","scopeid"),
+ true, true),
+ StructRef => ("struct_ref",
+ vec!("refid","refidcrate","qualname","scopeid"),
+ true, true),
+ FnRef => ("fn_ref", vec!("refid","refidcrate","qualname","scopeid"), true, true)
+ }
+ }
+
+ pub fn make_values_str(&self,
+ kind: &'static str,
+ fields: &Vec<&'static str>,
+ values: Vec<String>,
+ span: Span) -> Option<String> {
+ if values.len() != fields.len() {
+ self.span.sess.span_bug(span, format!(
+ "Mismatch between length of fields for '{}', expected '{}', found '{}'",
+ kind, fields.len(), values.len()).as_slice());
+ }
+
+ let values = values.iter().map(|s| {
+ if s.len() > 1020 {
+ s.as_slice().slice_to(1020)
+ } else {
+ s.as_slice()
+ }
+ });
+
+ let pairs = fields.iter().zip(values);
+ let mut strs = pairs.map(|(f, v)| format!(",{},\"{}\"", f, escape(
+ if *f == "qualname" {
+ self.krate.clone().append("::").append(v)
+ } else {
+ String::from_str(v)
+ }
+ )));
+ Some(strs.fold(String::new(), |s, ss| s.append(ss.as_slice()))).map(|s| s.into_owned())
+ }
+
+ pub fn record_without_span(&mut self,
+ kind: Row,
+ values: Vec<String>,
+ span: Span) {
+ let (label, ref fields, needs_span, dump_spans) = FmtStrs::lookup_row(kind);
+
+ if needs_span {
+ self.span.sess.span_bug(span, format!(
+ "Called record_without_span for '{}' which does requires a span",
+ label).as_slice());
+ }
+ assert!(!dump_spans);
+
+ if self.recorder.dump_spans {
+ return;
+ }
+
+ let values_str = match self.make_values_str(label, fields, values, span) {
+ Some(vs) => vs,
+ None => return,
+ };
+
+ let result = String::from_str(label);
+ self.recorder.record(result.append(values_str.as_slice()).append("\n").as_slice());
+ }
+
+ pub fn record_with_span(&mut self,
+ kind: Row,
+ span: Span,
+ sub_span: Span,
+ values: Vec<String>) {
+ let (label, ref fields, needs_span, dump_spans) = FmtStrs::lookup_row(kind);
+
+ if self.recorder.dump_spans {
+ if dump_spans {
+ self.recorder.dump_span(self.span, label, span, Some(sub_span));
+ }
+ return;
+ }
+
+ if !needs_span {
+ self.span.sess.span_bug(span,
+ format!("Called record_with_span for '{}' \
+ which does not require a span", label).as_slice());
+ }
+
+ let values_str = match self.make_values_str(label, fields, values, span) {
+ Some(vs) => vs,
+ None => return,
+ };
+ let result = format!("{},{}{}\n", label, self.span.extent_str(sub_span), values_str);
+ self.recorder.record(result.as_slice());
+ }
+
+ pub fn check_and_record(&mut self,
+ kind: Row,
+ span: Span,
+ sub_span: Option<Span>,
+ values: Vec<String>) {
+ match sub_span {
+ Some(sub_span) => self.record_with_span(kind, span, sub_span, values),
+ None => {
+ let (label, _, _, _) = FmtStrs::lookup_row(kind);
+ self.span.report_span_err(label, span);
+ }
+ }
+ }
+
+ pub fn variable_str(&mut self,
+ span: Span,
+ sub_span: Option<Span>,
+ id: NodeId,
+ name: &str,
+ value: &str,
+ typ: &str) {
+ // Getting a fully qualified name for a variable is hard because in
+ // the local case they can be overridden in one block and there is no nice way
+ // to refer to such a scope in english, so we just hack it by appending the
+ // variable def's node id
+ let qualname = String::from_str(name).append("$").append(id.to_str().as_slice());
+ self.check_and_record(Variable,
+ span,
+ sub_span,
+ svec!(id, name, qualname, value, typ, 0));
+ }
+
+ // formal parameters
+ pub fn formal_str(&mut self,
+ span: Span,
+ sub_span: Option<Span>,
+ id: NodeId,
+ fn_name: &str,
+ name: &str,
+ typ: &str) {
+ let qualname = String::from_str(fn_name).append("::").append(name);
+ self.check_and_record(Variable,
+ span,
+ sub_span,
+ svec!(id, name, qualname, "", typ, 0));
+ }
+
+ // value is the initialising expression of the static if it is not mut, otherwise "".
+ pub fn static_str(&mut self,
+ span: Span,
+ sub_span: Option<Span>,
+ id: NodeId,
+ name: &str,
+ qualname: &str,
+ value: &str,
+ typ: &str,
+ scope_id: NodeId) {
+ self.check_and_record(Variable,
+ span,
+ sub_span,
+ svec!(id, name, qualname, value, typ, scope_id));
+ }
+
+ pub fn field_str(&mut self,
+ span: Span,
+ sub_span: Option<Span>,
+ id: NodeId,
+ name: &str,
+ qualname: &str,
+ typ: &str,
+ scope_id: NodeId) {
+ self.check_and_record(Variable,
+ span,
+ sub_span,
+ svec!(id, name, qualname, "", typ, scope_id));
+ }
+
+ pub fn enum_str(&mut self,
+ span: Span,
+ sub_span: Option<Span>,
+ id: NodeId,
+ name: &str,
+ scope_id: NodeId) {
+ self.check_and_record(Enum,
+ span,
+ sub_span,
+ svec!(id, name, scope_id));
+ }
+
+ pub fn tuple_variant_str(&mut self,
+ span: Span,
+ sub_span: Option<Span>,
+ id: NodeId,
+ name: &str,
+ qualname: &str,
+ val: &str,
+ scope_id: NodeId) {
+ self.check_and_record(Variant,
+ span,
+ sub_span,
+ svec!(id, name, qualname, val, scope_id));
+ }
+
+ pub fn struct_variant_str(&mut self,
+ span: Span,
+ sub_span: Option<Span>,
+ id: NodeId,
+ ctor_id: NodeId,
+ name: &str,
+ val: &str,
+ scope_id: NodeId) {
+ self.check_and_record(VariantStruct,
+ span,
+ sub_span,
+ svec!(id, ctor_id, name, val, scope_id));
+ }
+
+ pub fn fn_str(&mut self,
+ span: Span,
+ sub_span: Option<Span>,
+ id: NodeId,
+ name: &str,
+ scope_id: NodeId) {
+ self.check_and_record(Function,
+ span,
+ sub_span,
+ svec!(id, name, "", "", scope_id));
+ }
+
+ pub fn method_str(&mut self,
+ span: Span,
+ sub_span: Option<Span>,
+ id: NodeId,
+ name: &str,
+ decl_id: Option<DefId>,
+ scope_id: NodeId) {
+ let values = match decl_id {
+ Some(decl_id) => svec!(id, name, decl_id.node, decl_id.krate, scope_id),
+ None => svec!(id, name, "", "", scope_id)
+ };
+ self.check_and_record(Function,
+ span,
+ sub_span,
+ values);
+ }
+
+ pub fn method_decl_str(&mut self,
+ span: Span,
+ sub_span: Option<Span>,
+ id: NodeId,
+ name: &str,
+ scope_id: NodeId) {
+ self.check_and_record(MethodDecl,
+ span,
+ sub_span,
+ svec!(id, name, scope_id));
+ }
+
+ pub fn struct_str(&mut self,
+ span: Span,
+ sub_span: Option<Span>,
+ id: NodeId,
+ ctor_id: NodeId,
+ name: &str,
+ scope_id: NodeId) {
+ self.check_and_record(Struct,
+ span,
+ sub_span,
+ svec!(id, ctor_id, name, scope_id));
+ }
+
+ pub fn trait_str(&mut self,
+ span: Span,
+ sub_span: Option<Span>,
+ id: NodeId,
+ name: &str,
+ scope_id: NodeId) {
+ self.check_and_record(Trait,
+ span,
+ sub_span,
+ svec!(id, name, scope_id));
+ }
+
+ pub fn impl_str(&mut self,
+ span: Span,
+ sub_span: Option<Span>,
+ id: NodeId,
+ ref_id: DefId,
+ scope_id: NodeId) {
+ self.check_and_record(Impl,
+ span,
+ sub_span,
+ svec!(id, ref_id.node, ref_id.krate, scope_id));
+ }
+
+ pub fn mod_str(&mut self,
+ span: Span,
+ sub_span: Option<Span>,
+ id: NodeId,
+ name: &str,
+ parent: NodeId,
+ filename: &str) {
+ self.check_and_record(Module,
+ span,
+ sub_span,
+ svec!(id, name, parent, filename));
+ }
+
+ pub fn use_alias_str(&mut self,
+ span: Span,
+ sub_span: Option<Span>,
+ id: NodeId,
+ mod_id: Option<DefId>,
+ name: &str,
+ parent: NodeId) {
+ let (mod_node, mod_crate) = match mod_id {
+ Some(mod_id) => (mod_id.node, mod_id.krate),
+ None => (0, 0)
+ };
+ self.check_and_record(UseAlias,
+ span,
+ sub_span,
+ svec!(id, mod_node, mod_crate, name, parent));
+ }
+
+ pub fn extern_crate_str(&mut self,
+ span: Span,
+ sub_span: Option<Span>,
+ id: NodeId,
+ cnum: ast::CrateNum,
+ name: &str,
+ loc: &str,
+ parent: NodeId) {
+ self.check_and_record(ExternCrate,
+ span,
+ sub_span,
+ svec!(id, name, loc, cnum, parent));
+ }
+
+ pub fn inherit_str(&mut self,
+ span: Span,
+ sub_span: Option<Span>,
+ base_id: DefId,
+ deriv_id: NodeId) {
+ self.check_and_record(Inheritance,
+ span,
+ sub_span,
+ svec!(base_id.node, base_id.krate, deriv_id, 0));
+ }
+
+ pub fn fn_call_str(&mut self,
+ span: Span,
+ sub_span: Option<Span>,
+ id: DefId,
+ scope_id:NodeId) {
+ self.check_and_record(FnCall,
+ span,
+ sub_span,
+ svec!(id.node, id.krate, "", scope_id));
+ }
+
+ pub fn meth_call_str(&mut self,
+ span: Span,
+ sub_span: Option<Span>,
+ defid: Option<DefId>,
+ declid: Option<DefId>,
+ scope_id: NodeId) {
+ let (dfn, dfk) = match defid {
+ Some(defid) => (defid.node, defid.krate),
+ None => (0, 0)
+ };
+ let (dcn, dck) = match declid {
+ Some(declid) => (s!(declid.node), s!(declid.krate)),
+ None => ("".to_owned(), "".to_owned())
+ };
+ self.check_and_record(MethodCall,
+ span,
+ sub_span,
+ svec!(dfn, dfk, dcn, dck, scope_id));
+ }
+
+ pub fn sub_mod_ref_str(&mut self,
+ span: Span,
+ sub_span: Span,
+ qualname: &str,
+ parent:NodeId) {
+ self.record_with_span(ModRef,
+ span,
+ sub_span,
+ svec!(0, 0, qualname, parent));
+ }
+
+ pub fn typedef_str(&mut self,
+ span: Span,
+ sub_span: Option<Span>,
+ id: NodeId,
+ qualname: &str,
+ value: &str) {
+ self.check_and_record(Typedef,
+ span,
+ sub_span,
+ svec!(id, qualname, value));
+ }
+
+ pub fn crate_str(&mut self,
+ span: Span,
+ name: &str) {
+ self.record_with_span(Crate,
+ span,
+ span,
+ svec!(name));
+ }
+
+ pub fn external_crate_str(&mut self,
+ span: Span,
+ name: &str,
+ num: ast::CrateNum) {
+ let lo_loc = self.span.sess.codemap().lookup_char_pos(span.lo);
+ self.record_without_span(ExternalCrate,
+ svec!(name, num, lo_loc.file.name),
+ span);
+ }
+
+ pub fn sub_type_ref_str(&mut self,
+ span: Span,
+ sub_span: Span,
+ qualname: &str) {
+ self.record_with_span(TypeRef,
+ span,
+ sub_span,
+ svec!(0, 0, qualname, 0));
+ }
+
+ // A slightly generic function for a reference to an item of any kind.
+ pub fn ref_str(&mut self,
+ kind: Row,
+ span: Span,
+ sub_span: Option<Span>,
+ id: DefId,
+ scope_id: NodeId) {
+ self.check_and_record(kind,
+ span,
+ sub_span,
+ svec!(id.node, id.krate, "", scope_id));
+ }
+}
--- /dev/null
+// 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.
+
+use driver::session::Session;
+
+use middle::save::generated_code;
+
+use std::cell::Cell;
+
+use syntax::ast;
+use syntax::codemap::*;
+use syntax::parse::lexer;
+use syntax::parse::lexer::{Reader,StringReader};
+use syntax::parse::token;
+use syntax::parse::token::{is_keyword,keywords,is_ident,Token};
+
+pub struct SpanUtils<'a> {
+ pub sess: &'a Session,
+ pub err_count: Cell<int>,
+}
+
+impl<'a> SpanUtils<'a> {
+ // Standard string for extents/location.
+ pub fn extent_str(&self, span: Span) -> String {
+ let lo_loc = self.sess.codemap().lookup_char_pos(span.lo);
+ let hi_loc = self.sess.codemap().lookup_char_pos(span.hi);
+ let lo_pos = self.sess.codemap().lookup_byte_offset(span.lo).pos;
+ let hi_pos = self.sess.codemap().lookup_byte_offset(span.hi).pos;
+
+ format!("file_name,{},file_line,{},file_col,{},extent_start,{},\
+ file_line_end,{},file_col_end,{},extent_end,{}",
+ lo_loc.file.name, lo_loc.line, lo_loc.col.to_uint(), lo_pos.to_uint(),
+ hi_loc.line, hi_loc.col.to_uint(), hi_pos.to_uint())
+ }
+
+ // sub_span starts at span.lo, so we need to adjust the positions etc.
+ // If sub_span is None, we don't need to adjust.
+ pub fn make_sub_span(&self, span: Span, sub_span: Option<Span>) -> Option<Span> {
+ let loc = self.sess.codemap().lookup_char_pos(span.lo);
+ assert!(!generated_code(span),
+ "generated code; we should not be processing this `{}` in {}, line {}",
+ self.snippet(span), loc.file.name, loc.line);
+
+ match sub_span {
+ None => None,
+ Some(sub) => {
+ let FileMapAndBytePos {fm, pos} =
+ self.sess.codemap().lookup_byte_offset(span.lo);
+ let base = pos + fm.start_pos;
+ Some(Span {
+ lo: base + self.sess.codemap().lookup_byte_offset(sub.lo).pos,
+ hi: base + self.sess.codemap().lookup_byte_offset(sub.hi).pos,
+ expn_info: None,
+ })
+ }
+ }
+ }
+
+ pub fn snippet(&self, span: Span) -> String {
+ match self.sess.codemap().span_to_snippet(span) {
+ Some(s) => s,
+ None => String::new(),
+ }
+ }
+
+ pub fn retokenise_span(&self, span: Span) -> StringReader<'a> {
+ // sadness - we don't have spans for sub-expressions nor access to the tokens
+ // so in order to get extents for the function name itself (which dxr expects)
+ // we need to re-tokenise the fn definition
+
+ // Note: this is a bit awful - it adds the contents of span to the end of
+ // the codemap as a new filemap. This is mostly OK, but means we should
+ // not iterate over the codemap. Also, any spans over the new filemap
+ // are incompatible with spans over other filemaps.
+ let filemap = self.sess.codemap().new_filemap(String::from_str("<anon-dxr>"),
+ self.snippet(span));
+ let s = self.sess;
+ lexer::StringReader::new(s.diagnostic(), filemap)
+ }
+
+ // Re-parses a path and returns the span for the last identifier in the path
+ pub fn span_for_last_ident(&self, span: Span) -> Option<Span> {
+ let mut result = None;
+
+ let mut toks = self.retokenise_span(span);
+ let mut bracket_count = 0;
+ loop {
+ let ts = toks.next_token();
+ if ts.tok == token::EOF {
+ return self.make_sub_span(span, result)
+ }
+ if bracket_count == 0 &&
+ (is_ident(&ts.tok) || is_keyword(keywords::Self, &ts.tok)) {
+ result = Some(ts.sp);
+ }
+
+ bracket_count += match ts.tok {
+ token::LT => 1,
+ token::GT => -1,
+ token::BINOP(token::SHR) => -2,
+ _ => 0
+ }
+ }
+ }
+
+ // Return the span for the first identifier in the path.
+ pub fn span_for_first_ident(&self, span: Span) -> Option<Span> {
+ let mut toks = self.retokenise_span(span);
+ let mut bracket_count = 0;
+ loop {
+ let ts = toks.next_token();
+ if ts.tok == token::EOF {
+ return None;
+ }
+ if bracket_count == 0 &&
+ (is_ident(&ts.tok) || is_keyword(keywords::Self, &ts.tok)) {
+ return self.make_sub_span(span, Some(ts.sp));
+ }
+
+ bracket_count += match ts.tok {
+ token::LT => 1,
+ token::GT => -1,
+ token::BINOP(token::SHR) => -2,
+ _ => 0
+ }
+ }
+ }
+
+ // Return the span for the last ident before a `(` or `<` or '::<' and outside any
+ // any brackets, or the last span.
+ pub fn sub_span_for_meth_name(&self, span: Span) -> Option<Span> {
+ let mut toks = self.retokenise_span(span);
+ let mut prev = toks.next_token();
+ let mut result = None;
+ let mut bracket_count = 0;
+ let mut last_span = None;
+ while prev.tok != token::EOF {
+ last_span = None;
+ let mut next = toks.next_token();
+
+ if (next.tok == token::LPAREN ||
+ next.tok == token::LT) &&
+ bracket_count == 0 &&
+ is_ident(&prev.tok) {
+ result = Some(prev.sp);
+ }
+
+ if bracket_count == 0 &&
+ next.tok == token::MOD_SEP {
+ let old = prev;
+ prev = next;
+ next = toks.next_token();
+ if next.tok == token::LT &&
+ is_ident(&old.tok) {
+ result = Some(old.sp);
+ }
+ }
+
+ bracket_count += match prev.tok {
+ token::LPAREN | token::LT => 1,
+ token::RPAREN | token::GT => -1,
+ token::BINOP(token::SHR) => -2,
+ _ => 0
+ };
+
+ if is_ident(&prev.tok) && bracket_count == 0 {
+ last_span = Some(prev.sp);
+ }
+ prev = next;
+ }
+ if result.is_none() && last_span.is_some() {
+ return self.make_sub_span(span, last_span);
+ }
+ return self.make_sub_span(span, result);
+ }
+
+ // Return the span for the last ident before a `<` and outside any
+ // brackets, or the last span.
+ pub fn sub_span_for_type_name(&self, span: Span) -> Option<Span> {
+ let mut toks = self.retokenise_span(span);
+ let mut prev = toks.next_token();
+ let mut result = None;
+ let mut bracket_count = 0;
+ loop {
+ let next = toks.next_token();
+
+ if (next.tok == token::LT ||
+ next.tok == token::COLON) &&
+ bracket_count == 0 &&
+ is_ident(&prev.tok) {
+ result = Some(prev.sp);
+ }
+
+ bracket_count += match prev.tok {
+ token::LT => 1,
+ token::GT => -1,
+ token::BINOP(token::SHR) => -2,
+ _ => 0
+ };
+
+ if next.tok == token::EOF {
+ break;
+ }
+ prev = next;
+ }
+ if bracket_count != 0 {
+ let loc = self.sess.codemap().lookup_char_pos(span.lo);
+ self.sess.span_bug(span,
+ format!("Mis-counted brackets when breaking path? Parsing '{}' in {}, line {}",
+ self.snippet(span), loc.file.name, loc.line).as_slice());
+ }
+ if result.is_none() && is_ident(&prev.tok) && bracket_count == 0 {
+ return self.make_sub_span(span, Some(prev.sp));
+ }
+ self.make_sub_span(span, result)
+ }
+
+ // Reparse span and return an owned vector of sub spans of the first limit
+ // identifier tokens in the given nesting level.
+ // example with Foo<Bar<T,V>, Bar<T,V>>
+ // Nesting = 0: all idents outside of brackets: ~[Foo]
+ // Nesting = 1: idents within one level of brackets: ~[Bar, Bar]
+ pub fn spans_with_brackets(&self, span: Span, nesting: int, limit: int) -> Vec<Span> {
+ let mut result: Vec<Span> = vec!();
+
+ let mut toks = self.retokenise_span(span);
+ // We keep track of how many brackets we're nested in
+ let mut bracket_count = 0;
+ loop {
+ let ts = toks.next_token();
+ if ts.tok == token::EOF {
+ if bracket_count != 0 {
+ let loc = self.sess.codemap().lookup_char_pos(span.lo);
+ self.sess.span_bug(span, format!(
+ "Mis-counted brackets when breaking path? Parsing '{}' in {}, line {}",
+ self.snippet(span), loc.file.name, loc.line).as_slice());
+ }
+ return result
+ }
+ if (result.len() as int) == limit {
+ return result;
+ }
+ bracket_count += match ts.tok {
+ token::LT => 1,
+ token::GT => -1,
+ token::BINOP(token::SHL) => 2,
+ token::BINOP(token::SHR) => -2,
+ _ => 0
+ };
+ if is_ident(&ts.tok) &&
+ bracket_count == nesting {
+ result.push(self.make_sub_span(span, Some(ts.sp)).unwrap());
+ }
+ }
+ }
+
+ pub fn sub_span_before_token(&self, span: Span, tok: Token) -> Option<Span> {
+ let mut toks = self.retokenise_span(span);
+ let mut prev = toks.next_token();
+ loop {
+ if prev.tok == token::EOF {
+ return None;
+ }
+ let next = toks.next_token();
+ if next.tok == tok {
+ return self.make_sub_span(span, Some(prev.sp));
+ }
+ prev = next;
+ }
+ }
+
+ // Return an owned vector of the subspans of the tokens that come before tok2
+ // which is before tok1. If there is no instance of tok2 before tok1, then that
+ // place in the result is None.
+ // Everything returned must be inside a set of (non-angle) brackets, but no
+ // more deeply nested than that.
+ pub fn sub_spans_before_tokens(&self,
+ span: Span,
+ tok1: Token,
+ tok2: Token) -> Vec<Option<Span>> {
+ let mut sub_spans : Vec<Option<Span>> = vec!();
+ let mut toks = self.retokenise_span(span);
+ let mut prev = toks.next_token();
+ let mut next = toks.next_token();
+ let mut stored_val = false;
+ let mut found_val = false;
+ let mut bracket_count = 0;
+ while next.tok != token::EOF {
+ if bracket_count == 1 {
+ if next.tok == tok2 {
+ sub_spans.push(self.make_sub_span(span, Some(prev.sp)));
+ stored_val = true;
+ found_val = false;
+ }
+ if next.tok == tok1 {
+ if !stored_val {
+ sub_spans.push(None);
+ } else {
+ stored_val = false;
+ }
+ found_val = false;
+ }
+ if !stored_val &&
+ is_ident(&next.tok) {
+ found_val = true;
+ }
+ }
+
+ bracket_count += match next.tok {
+ token::LPAREN | token::LBRACE => 1,
+ token::RPAREN | token::RBRACE => -1,
+ _ => 0
+ };
+
+ prev = next;
+ next = toks.next_token();
+ }
+ if found_val {
+ sub_spans.push(None);
+ }
+ return sub_spans;
+ }
+
+ pub fn sub_span_after_keyword(&self,
+ span: Span,
+ keyword: keywords::Keyword) -> Option<Span> {
+ let mut toks = self.retokenise_span(span);
+ loop {
+ let ts = toks.next_token();
+ if ts.tok == token::EOF {
+ return None;
+ }
+ if is_keyword(keyword, &ts.tok) {
+ let ts = toks.next_token();
+ if ts.tok == token::EOF {
+ return None
+ } else {
+ return self.make_sub_span(span, Some(ts.sp));
+ }
+ }
+ }
+ }
+
+ // Returns a list of the spans of idents in a patch.
+ // E.g., For foo::bar<x,t>::baz, we return [foo, bar, baz] (well, their spans)
+ pub fn spans_for_path_segments(&self, path: &ast::Path) -> Vec<Span> {
+ if generated_code(path.span) {
+ return vec!();
+ }
+
+ self.spans_with_brackets(path.span, 0, -1)
+ }
+
+ // Return an owned vector of the subspans of the param identifier
+ // tokens found in span.
+ pub fn spans_for_ty_params(&self, span: Span, number: int) -> Vec<Span> {
+ if generated_code(span) {
+ return vec!();
+ }
+ // Type params are nested within one level of brackets:
+ // i.e. we want ~[A, B] from Foo<A, B<T,U>>
+ self.spans_with_brackets(span, 1, number)
+ }
+
+ pub fn report_span_err(&self, kind: &str, span: Span) {
+ let loc = self.sess.codemap().lookup_char_pos(span.lo);
+ info!("({}) Could not find sub_span in `{}` in {}, line {}",
+ kind, self.snippet(span), loc.file.name, loc.line);
+ self.err_count.set(self.err_count.get()+1);
+ if self.err_count.get() > 1000 {
+ self.sess.bug("span errors reached 1000, giving up");
+ }
+ }
+}
`llvm.dbg.declare` instructions to the correct source locations even while source location emission
is still disabled, so there is no need to do anything special with source location handling here.
+## Unique Type Identification
+In order for link-time optimization to work properly, LLVM needs a unique type identifier that tells
+it across compilation units which types are the same as others. This type identifier is created by
+TypeMap::get_unique_type_id_of_type() using the following algorithm:
+
+(1) Primitive types have their name as ID
+(2) Structs, enums and traits have a multipart identifier
+ (1) The first part is the SVH (strict version hash) of the crate they were originally defined in
+ (2) The second part is the ast::NodeId of the definition in their original crate
+ (3) The final part is a concatenation of the type IDs of their concrete type arguments if they
+ are generic types.
+(3) Tuple-, pointer and function types are structurally identified, which means that they are
+ equivalent if their component types are equivalent (i.e. (int, int) is the same regardless in
+ which crate it is used).
+
+This algorithm also provides a stable ID for types that are defined in one crate but instantiated
+from metadata within another crate. We just have to take care to always map crate and node IDs back
+to the original crate context.
+
+As a side-effect these unique type IDs also help to solve a problem arising from lifetime
+parameters. Since lifetime parameters are completely omitted in debuginfo, more than one `ty::t`
+instance may map to the same debuginfo type metadata, that is, some struct `Struct<'a>` may have N
+instantiations with different concrete substitutions for `'a`, and thus there will be N `ty::t`
+instances for the type `Struct<'a>` even though it is not generic otherwise. Unfortunately this
+means that we cannot use `ty::type_id()` as cheap identifier for type metadata---we have done this
+in the past, but it led to unnecessary metadata duplication in the best case and LLVM assertions in
+the worst. However, the unique type ID as described above *can* be used as identifier. Since it is
+comparatively expensive to construct, though, `ty::type_id()` is still used additionally as an
+optimization for cases where the exact same type has been seen before (which is most of the time).
*/
-
use driver::config;
use driver::config::{FullDebugInfo, LimitedDebugInfo, NoDebugInfo};
use lib::llvm::llvm;
use std::gc::Gc;
use std::ptr;
use std::rc::{Rc, Weak};
-use std::sync::atomics;
+use syntax::util::interner::Interner;
use syntax::codemap::{Span, Pos};
use syntax::{abi, ast, codemap, ast_util, ast_map};
use syntax::owned_slice::OwnedSlice;
static DW_ATE_boolean: c_uint = 0x02;
static DW_ATE_float: c_uint = 0x04;
static DW_ATE_signed: c_uint = 0x05;
-// static DW_ATE_signed_char: c_uint = 0x06;
static DW_ATE_unsigned: c_uint = 0x07;
static DW_ATE_unsigned_char: c_uint = 0x08;
// Public Interface of debuginfo module
//=-------------------------------------------------------------------------------------------------
+#[deriving(Copy, Show, Hash, Eq, PartialEq, Clone)]
+struct UniqueTypeId(ast::Name);
+
+// The TypeMap is where the CrateDebugContext holds the type metadata nodes created so far. The
+// metadata nodes are indexed by UniqueTypeId, and, for faster lookup, also by ty::t. The
+// TypeMap is responsible for creating UniqueTypeIds.
+struct TypeMap {
+ // The UniqueTypeIds created so far
+ unique_id_interner: Interner<Rc<String>>,
+ // A map from UniqueTypeId to debuginfo metadata for that type. This is a 1:1 mapping.
+ unique_id_to_metadata: HashMap<UniqueTypeId, DIType>,
+ // A map from ty::type_id() to debuginfo metadata. This is a N:1 mapping.
+ type_to_metadata: HashMap<uint, DIType>,
+ // A map from ty::type_id() to UniqueTypeId. This is a N:1 mapping.
+ type_to_unique_id: HashMap<uint, UniqueTypeId>
+}
+
+impl TypeMap {
+
+ fn new() -> TypeMap {
+ TypeMap {
+ unique_id_interner: Interner::new(),
+ type_to_metadata: HashMap::new(),
+ unique_id_to_metadata: HashMap::new(),
+ type_to_unique_id: HashMap::new(),
+ }
+ }
+
+ // Adds a ty::t to metadata mapping to the TypeMap. The method will fail if the mapping already
+ // exists.
+ fn register_type_with_metadata(&mut self,
+ cx: &CrateContext,
+ type_: ty::t,
+ metadata: DIType) {
+ if !self.type_to_metadata.insert(ty::type_id(type_), metadata) {
+ cx.sess().bug(format!("Type metadata for ty::t '{}' is already in the TypeMap!",
+ ppaux::ty_to_str(cx.tcx(), type_)).as_slice());
+ }
+ }
+
+ // Adds a UniqueTypeId to metadata mapping to the TypeMap. The method will fail if the mapping
+ // already exists.
+ fn register_unique_id_with_metadata(&mut self,
+ cx: &CrateContext,
+ unique_type_id: UniqueTypeId,
+ metadata: DIType) {
+ if !self.unique_id_to_metadata.insert(unique_type_id, metadata) {
+ let unique_type_id_str = self.get_unique_type_id_as_string(unique_type_id);
+ cx.sess().bug(format!("Type metadata for unique id '{}' is already in the TypeMap!",
+ unique_type_id_str.as_slice()).as_slice());
+ }
+ }
+
+ fn find_metadata_for_type(&self, type_: ty::t) -> Option<DIType> {
+ self.type_to_metadata.find_copy(&ty::type_id(type_))
+ }
+
+ fn find_metadata_for_unique_id(&self, unique_type_id: UniqueTypeId) -> Option<DIType> {
+ self.unique_id_to_metadata.find_copy(&unique_type_id)
+ }
+
+ // Get the string representation of a UniqueTypeId. This method will fail if the id is unknown.
+ fn get_unique_type_id_as_string(&self, unique_type_id: UniqueTypeId) -> Rc<String> {
+ let UniqueTypeId(interner_key) = unique_type_id;
+ self.unique_id_interner.get(interner_key)
+ }
+
+ // Get the UniqueTypeId for the given type. If the UniqueTypeId for the given type has been
+ // requested before, this is just a table lookup. Otherwise an ID will be generated and stored
+ // for later lookup.
+ fn get_unique_type_id_of_type(&mut self, cx: &CrateContext, type_: ty::t) -> UniqueTypeId {
+
+ // basic type -> {:name of the type:}
+ // tuple -> {tuple_(:param-uid:)*}
+ // struct -> {struct_:svh: / :node-id:_<(:param-uid:),*> }
+ // enum -> {enum_:svh: / :node-id:_<(:param-uid:),*> }
+ // enum variant -> {variant_:variant-name:_:enum-uid:}
+ // reference (&) -> {& :pointee-uid:}
+ // mut reference (&mut) -> {&mut :pointee-uid:}
+ // ptr (*) -> {* :pointee-uid:}
+ // mut ptr (*mut) -> {*mut :pointee-uid:}
+ // unique ptr (~) -> {~ :pointee-uid:}
+ // @-ptr (@) -> {@ :pointee-uid:}
+ // sized vec ([T, ..x]) -> {[:size:] :element-uid:}
+ // vec slice (&[T]) -> {&<mut> [] :element-uid:}
+ // trait (~ | &[mut] T) -> {:sigil: trait_:svh: / :node-id:_<(:param-uid:),*> }
+ // closure -> {<unsafe_> <once_> :store-sigil: |(:param-uid:),* <,_...>| -> \
+ // :return-type-uid: : (:bounds:)*}
+ // function -> {<unsafe_> <abi_> fn( (:param-uid:)* <,_...> ) -> \
+ // :return-type-uid:}
+
+ match self.type_to_unique_id.find_copy(&ty::type_id(type_)) {
+ Some(unique_type_id) => return unique_type_id,
+ None => { /* generate one */}
+ };
+
+ let mut unique_type_id = String::with_capacity(256);
+ unique_type_id.push_char('{');
+
+ match ty::get(type_).sty {
+ ty::ty_nil |
+ ty::ty_bot |
+ ty::ty_bool |
+ ty::ty_char |
+ ty::ty_str |
+ ty::ty_int(_) |
+ ty::ty_uint(_) |
+ ty::ty_float(_) => {
+ unique_type_id.push_str(ppaux::ty_to_str(cx.tcx(), type_).as_slice());
+ },
+ ty::ty_enum(def_id, ref substs) => {
+ unique_type_id.push_str("enum ");
+ from_def_id_and_substs(self, cx, def_id, substs, &mut unique_type_id);
+ },
+ ty::ty_struct(def_id, ref substs) => {
+ unique_type_id.push_str("struct ");
+ from_def_id_and_substs(self, cx, def_id, substs, &mut unique_type_id);
+ },
+ ty::ty_tup(ref component_types) => {
+ unique_type_id.push_str("tuple ");
+ for &component_type in component_types.iter() {
+ let component_type_id = self.get_unique_type_id_of_type(cx, component_type);
+ let component_type_id = self.get_unique_type_id_as_string(component_type_id);
+ unique_type_id.push_str(component_type_id.as_slice());
+ }
+ },
+ ty::ty_box(inner_type) => {
+ unique_type_id.push_char('@');
+ let inner_type_id = self.get_unique_type_id_of_type(cx, inner_type);
+ let inner_type_id = self.get_unique_type_id_as_string(inner_type_id);
+ unique_type_id.push_str(inner_type_id.as_slice());
+ },
+ ty::ty_uniq(inner_type) => {
+ unique_type_id.push_char('~');
+ let inner_type_id = self.get_unique_type_id_of_type(cx, inner_type);
+ let inner_type_id = self.get_unique_type_id_as_string(inner_type_id);
+ unique_type_id.push_str(inner_type_id.as_slice());
+ },
+ ty::ty_ptr(ty::mt { ty: inner_type, mutbl } ) => {
+ unique_type_id.push_char('*');
+ if mutbl == ast::MutMutable {
+ unique_type_id.push_str("mut");
+ }
+
+ let inner_type_id = self.get_unique_type_id_of_type(cx, inner_type);
+ let inner_type_id = self.get_unique_type_id_as_string(inner_type_id);
+ unique_type_id.push_str(inner_type_id.as_slice());
+ },
+ ty::ty_rptr(_, ty::mt { ty: inner_type, mutbl }) => {
+ unique_type_id.push_char('&');
+ if mutbl == ast::MutMutable {
+ unique_type_id.push_str("mut");
+ }
+
+ let inner_type_id = self.get_unique_type_id_of_type(cx, inner_type);
+ let inner_type_id = self.get_unique_type_id_as_string(inner_type_id);
+ unique_type_id.push_str(inner_type_id.as_slice());
+ },
+ ty::ty_vec(ty::mt { ty: inner_type, mutbl }, optional_length) => {
+ match optional_length {
+ Some(len) => {
+ unique_type_id.push_str(format!("[{}]", len).as_slice());
+ }
+ None => {
+ unique_type_id.push_char('&');
+
+ if mutbl == ast::MutMutable {
+ unique_type_id.push_str("mut");
+ }
+
+ unique_type_id.push_str("[]");
+ }
+ };
+
+ let inner_type_id = self.get_unique_type_id_of_type(cx, inner_type);
+ let inner_type_id = self.get_unique_type_id_as_string(inner_type_id);
+ unique_type_id.push_str(inner_type_id.as_slice());
+ },
+ ty::ty_trait(ref trait_data) => {
+ match trait_data.store {
+ ty::UniqTraitStore => unique_type_id.push_char('~'),
+ ty::RegionTraitStore(_, ast::MutMutable) => unique_type_id.push_str("&mut"),
+ ty::RegionTraitStore(_, ast::MutImmutable) => unique_type_id.push_char('&'),
+ };
+
+ unique_type_id.push_str("trait ");
+
+ from_def_id_and_substs(self,
+ cx,
+ trait_data.def_id,
+ &trait_data.substs,
+ &mut unique_type_id);
+ },
+ ty::ty_bare_fn(ty::BareFnTy{ fn_style, abi, ref sig } ) => {
+ if fn_style == ast::UnsafeFn {
+ unique_type_id.push_str("unsafe ");
+ }
+
+ unique_type_id.push_str(abi.name());
+
+ unique_type_id.push_str(" fn(");
+
+ for ¶meter_type in sig.inputs.iter() {
+ let parameter_type_id = self.get_unique_type_id_of_type(cx, parameter_type);
+ let parameter_type_id = self.get_unique_type_id_as_string(parameter_type_id);
+ unique_type_id.push_str(parameter_type_id.as_slice());
+ unique_type_id.push_char(',');
+ }
+
+ if sig.variadic {
+ unique_type_id.push_str("...");
+ }
+
+ unique_type_id.push_str(")->");
+ let return_type_id = self.get_unique_type_id_of_type(cx, sig.output);
+ let return_type_id = self.get_unique_type_id_as_string(return_type_id);
+ unique_type_id.push_str(return_type_id.as_slice());
+ },
+ ty::ty_closure(box ty::ClosureTy { fn_style,
+ onceness,
+ store,
+ ref bounds,
+ ref sig }) => {
+ if fn_style == ast::UnsafeFn {
+ unique_type_id.push_str("unsafe ");
+ }
+
+ if onceness == ast::Once {
+ unique_type_id.push_str("once ");
+ }
+
+ match store {
+ ty::UniqTraitStore => unique_type_id.push_str("~|"),
+ ty::RegionTraitStore(_, ast::MutMutable) => unique_type_id.push_str("&mut|"),
+ ty::RegionTraitStore(_, ast::MutImmutable) => unique_type_id.push_str("&|"),
+ };
+
+ for ¶meter_type in sig.inputs.iter() {
+ let parameter_type_id = self.get_unique_type_id_of_type(cx, parameter_type);
+ let parameter_type_id = self.get_unique_type_id_as_string(parameter_type_id);
+ unique_type_id.push_str(parameter_type_id.as_slice());
+ unique_type_id.push_char(',');
+ }
+
+ if sig.variadic {
+ unique_type_id.push_str("...");
+ }
+
+ unique_type_id.push_str("|->");
+
+ let return_type_id = self.get_unique_type_id_of_type(cx, sig.output);
+ let return_type_id = self.get_unique_type_id_as_string(return_type_id);
+ unique_type_id.push_str(return_type_id.as_slice());
+
+ unique_type_id.push_char(':');
+
+ for bound in bounds.iter() {
+ match bound {
+ ty::BoundStatic => unique_type_id.push_str("'static"),
+ ty::BoundSend => unique_type_id.push_str("Send"),
+ ty::BoundSized => unique_type_id.push_str("Sized"),
+ ty::BoundCopy => unique_type_id.push_str("Copy"),
+ ty::BoundShare => unique_type_id.push_str("Share"),
+ };
+ unique_type_id.push_char('+');
+ }
+ },
+ _ => {
+ cx.sess().bug(format!("get_unique_type_id_of_type() - unexpected type: {}, {:?}",
+ ppaux::ty_to_str(cx.tcx(), type_).as_slice(),
+ ty::get(type_).sty).as_slice())
+ }
+ };
+
+ unique_type_id.push_char('}');
+
+ // Trim to size before storing permanently
+ unique_type_id.shrink_to_fit();
+
+ let key = self.unique_id_interner.intern(Rc::new(unique_type_id));
+ self.type_to_unique_id.insert(ty::type_id(type_), UniqueTypeId(key));
+
+ return UniqueTypeId(key);
+
+ fn from_def_id_and_substs(type_map: &mut TypeMap,
+ cx: &CrateContext,
+ def_id: ast::DefId,
+ substs: &subst::Substs,
+ output: &mut String) {
+ use std::num::ToStrRadix;
+
+ // First, find out the 'real' def_id of the type. Items inlined from other crates have
+ // to be mapped back to their source.
+ let source_def_id = if def_id.krate == ast::LOCAL_CRATE {
+ match cx.external_srcs.borrow().find_copy(&def_id.node) {
+ Some(source_def_id) => {
+ // The given def_id identifies the inlined copy of a type definition,
+ // let's take the source of the copy
+ source_def_id
+ }
+ None => def_id
+ }
+ } else {
+ def_id
+ };
+
+ // Get the crate hash as first part of the identifier
+ let crate_hash = if source_def_id.krate == ast::LOCAL_CRATE {
+ cx.link_meta.crate_hash.clone()
+ } else {
+ cx.sess().cstore.get_crate_hash(source_def_id.krate)
+ };
+
+ output.push_str(crate_hash.as_str());
+ output.push_str("/");
+ output.push_str(def_id.node.to_str_radix(16).as_slice());
+
+ // Maybe check that there is no self type here
+
+ if substs.tps.len() > 0 {
+ output.push_char('<');
+
+ for &type_parameter in substs.tps.iter() {
+ let param_type_id = type_map.get_unique_type_id_of_type(cx, type_parameter);
+ let param_type_id = type_map.get_unique_type_id_as_string(param_type_id);
+ output.push_str(param_type_id.as_slice());
+ output.push_char(',');
+ }
+
+ output.push_char('>');
+ }
+ }
+ }
+
+ // Get the UniqueTypeId for an enum variant. Enum variants are not really types of their own,
+ // so they need special handling. We still need a UniqueTypeId for them, since to debuginfo they
+ // *are* real types.
+ fn get_unique_type_id_of_enum_variant(&mut self,
+ cx: &CrateContext,
+ enum_type: ty::t,
+ variant_name: &str)
+ -> UniqueTypeId {
+ let enum_type_id = self.get_unique_type_id_of_type(cx, enum_type);
+ let enum_variant_type_id = format!("{}::{}",
+ self.get_unique_type_id_as_string(enum_type_id)
+ .as_slice(),
+ variant_name);
+ let interner_key = self.unique_id_interner.intern(Rc::new(enum_variant_type_id));
+ UniqueTypeId(interner_key)
+ }
+}
+
+
/// A context object for maintaining all state needed by the debuginfo module.
pub struct CrateDebugContext {
llcontext: ContextRef,
builder: DIBuilderRef,
current_debug_location: Cell<DebugLocation>,
created_files: RefCell<HashMap<String, DIFile>>,
- created_types: RefCell<HashMap<uint, DIType>>,
created_enum_disr_types: RefCell<HashMap<ast::DefId, DIType>>,
+
+ type_map: RefCell<TypeMap>,
namespace_map: RefCell<HashMap<Vec<ast::Name>, Rc<NamespaceTreeNode>>>,
+
// This collection is used to assert that composite types (structs, enums, ...) have their
// members only set once:
composite_types_completed: RefCell<HashSet<DIType>>,
builder: builder,
current_debug_location: Cell::new(UnknownLocation),
created_files: RefCell::new(HashMap::new()),
- created_types: RefCell::new(HashMap::new()),
created_enum_disr_types: RefCell::new(HashMap::new()),
+ type_map: RefCell::new(TypeMap::new()),
namespace_map: RefCell::new(HashMap::new()),
composite_types_completed: RefCell::new(HashSet::new()),
};
// more information.
enum RecursiveTypeDescription {
UnfinishedMetadata {
- cache_id: uint,
+ unfinished_type: ty::t,
+ unique_type_id: UniqueTypeId,
metadata_stub: DICompositeType,
llvm_type: Type,
file_metadata: DIFile,
FinalMetadata(DICompositeType)
}
+fn create_and_register_recursive_type_forward_declaration(
+ cx: &CrateContext,
+ unfinished_type: ty::t,
+ unique_type_id: UniqueTypeId,
+ metadata_stub: DICompositeType,
+ llvm_type: Type,
+ file_metadata: DIFile,
+ member_description_factory: MemberDescriptionFactory)
+ -> RecursiveTypeDescription {
+
+ // Insert the stub into the TypeMap in order to allow for recursive references
+ let mut type_map = debug_context(cx).type_map.borrow_mut();
+ type_map.register_unique_id_with_metadata(cx, unique_type_id, metadata_stub);
+ type_map.register_type_with_metadata(cx, unfinished_type, metadata_stub);
+
+ UnfinishedMetadata {
+ unfinished_type: unfinished_type,
+ unique_type_id: unique_type_id,
+ metadata_stub: metadata_stub,
+ llvm_type: llvm_type,
+ file_metadata: file_metadata,
+ member_description_factory: member_description_factory,
+ }
+}
+
impl RecursiveTypeDescription {
// Finishes up the description of the type in question (mostly by providing descriptions of the
// fields of the given type) and returns the final type metadata.
match *self {
FinalMetadata(metadata) => metadata,
UnfinishedMetadata {
- cache_id,
+ unfinished_type,
+ unique_type_id,
metadata_stub,
llvm_type,
file_metadata,
ref member_description_factory
} => {
- // Insert the stub into the cache in order to allow recursive references ...
- debug_context(cx).created_types.borrow_mut()
- .insert(cache_id, metadata_stub);
+ // Make sure that we have a forward declaration of the type in the TypeMap so that
+ // recursive references are possible. This will always be the case if the
+ // RecursiveTypeDescription has been properly created through the
+ // create_and_register_recursive_type_forward_declaration() function.
+ {
+ let type_map = debug_context(cx).type_map.borrow();
+ if type_map.find_metadata_for_unique_id(unique_type_id).is_none() ||
+ type_map.find_metadata_for_type(unfinished_type).is_none() {
+ cx.sess().bug(format!("Forward declaration of potentially recursive type \
+ '{}' was not found in TypeMap!",
+ ppaux::ty_to_str(cx.tcx(), unfinished_type))
+ .as_slice());
+ }
+ }
// ... then create the member descriptions ...
let member_descriptions = member_description_factory.create_member_descriptions(cx);
struct_type: ty::t,
def_id: ast::DefId,
substs: &subst::Substs,
+ unique_type_id: UniqueTypeId,
span: Span)
-> RecursiveTypeDescription {
let struct_name = ppaux::ty_to_str(cx.tcx(), struct_type);
let struct_metadata_stub = create_struct_stub(cx,
struct_llvm_type,
struct_name.as_slice(),
+ unique_type_id,
containing_scope,
file_metadata,
definition_span);
let fields = ty::struct_fields(cx.tcx(), def_id, substs);
- UnfinishedMetadata {
- cache_id: cache_id_for_type(struct_type),
- metadata_stub: struct_metadata_stub,
- llvm_type: struct_llvm_type,
- file_metadata: file_metadata,
- member_description_factory: StructMDF(StructMemberDescriptionFactory {
+ create_and_register_recursive_type_forward_declaration(
+ cx,
+ struct_type,
+ unique_type_id,
+ struct_metadata_stub,
+ struct_llvm_type,
+ file_metadata,
+ StructMDF(StructMemberDescriptionFactory {
fields: fields,
is_simd: ty::type_is_simd(cx.tcx(), struct_type),
span: span,
- }),
- }
+ })
+ )
}
fn prepare_tuple_metadata(cx: &CrateContext,
tuple_type: ty::t,
component_types: &[ty::t],
+ unique_type_id: UniqueTypeId,
span: Span)
-> RecursiveTypeDescription {
let tuple_name = ppaux::ty_to_str(cx.tcx(), tuple_type);
let loc = span_start(cx, span);
let file_metadata = file_metadata(cx, loc.file.name.as_slice());
- UnfinishedMetadata {
- cache_id: cache_id_for_type(tuple_type),
- metadata_stub: create_struct_stub(cx,
- tuple_llvm_type,
- tuple_name.as_slice(),
- file_metadata,
- file_metadata,
- span),
- llvm_type: tuple_llvm_type,
- file_metadata: file_metadata,
- member_description_factory: TupleMDF(TupleMemberDescriptionFactory {
+ create_and_register_recursive_type_forward_declaration(
+ cx,
+ tuple_type,
+ unique_type_id,
+ create_struct_stub(cx,
+ tuple_llvm_type,
+ tuple_name.as_slice(),
+ unique_type_id,
+ file_metadata,
+ file_metadata,
+ span),
+ tuple_llvm_type,
+ file_metadata,
+ TupleMDF(TupleMemberDescriptionFactory {
component_types: Vec::from_slice(component_types),
span: span,
})
- }
+ )
}
// variant of the given enum, this factory will produce one MemberDescription (all with no name and
// a fixed offset of zero bytes).
struct EnumMemberDescriptionFactory {
+ enum_type: ty::t,
type_rep: Rc<adt::Repr>,
variants: Rc<Vec<Rc<ty::VariantInfo>>>,
discriminant_type_metadata: Option<DIType>,
.map(|(i, struct_def)| {
let (variant_type_metadata, variant_llvm_type, member_desc_factory) =
describe_enum_variant(cx,
+ self.enum_type,
struct_def,
&**self.variants.get(i),
discriminant_info,
} else {
let (variant_type_metadata, variant_llvm_type, member_description_factory) =
describe_enum_variant(cx,
+ self.enum_type,
struct_def,
&**self.variants.get(0),
NoDiscriminant,
offset: FixedMemberOffset { bytes: 0 },
};
+ let unique_type_id = debug_context(cx).type_map
+ .borrow_mut()
+ .get_unique_type_id_of_enum_variant(
+ cx,
+ self.enum_type,
+ non_null_variant_name.get());
+
// Now we can create the metadata of the artificial struct
let artificial_struct_metadata =
composite_type_metadata(cx,
artificial_struct_llvm_type,
non_null_variant_name.get(),
+ unique_type_id,
&[sole_struct_member_description],
self.containing_scope,
self.file_metadata,
// Create a description of the non-null variant
let (variant_type_metadata, variant_llvm_type, member_description_factory) =
describe_enum_variant(cx,
+ self.enum_type,
struct_def,
&**self.variants.get(nndiscr as uint),
OptimizedDiscriminant(ptrfield),
// (3) a MemberDescriptionFactory for producing the descriptions of the fields of the variant. This
// is a rudimentary version of a full RecursiveTypeDescription.
fn describe_enum_variant(cx: &CrateContext,
+ enum_type: ty::t,
struct_def: &adt::Struct,
variant_info: &ty::VariantInfo,
discriminant_info: EnumDiscriminantInfo,
codemap::DUMMY_SP
};
+ let variant_name = token::get_ident(variant_info.name);
+ let variant_name = variant_name.get();
+ let unique_type_id = debug_context(cx).type_map
+ .borrow_mut()
+ .get_unique_type_id_of_enum_variant(
+ cx,
+ enum_type,
+ variant_name);
+
let metadata_stub = create_struct_stub(cx,
variant_llvm_type,
- token::get_ident(variant_info.name).get(),
+ variant_name,
+ unique_type_id,
containing_scope,
file_metadata,
variant_definition_span);
fn prepare_enum_metadata(cx: &CrateContext,
enum_type: ty::t,
enum_def_id: ast::DefId,
+ unique_type_id: UniqueTypeId,
span: Span)
-> RecursiveTypeDescription {
let enum_name = ppaux::ty_to_str(cx.tcx(), enum_type);
let enum_llvm_type = type_of::type_of(cx, enum_type);
let (enum_type_size, enum_type_align) = size_and_align_of(cx, enum_llvm_type);
- let unique_id = generate_unique_type_id("DI_ENUM_");
+
+ let unique_type_id_str = debug_context(cx)
+ .type_map
+ .borrow()
+ .get_unique_type_id_as_string(unique_type_id);
let enum_metadata = enum_name.as_slice().with_c_str(|enum_name| {
- unique_id.as_slice().with_c_str(|unique_id| {
+ unique_type_id_str.as_slice().with_c_str(|unique_type_id_str| {
unsafe {
llvm::LLVMDIBuilderCreateUnionType(
DIB(cx),
0, // Flags
ptr::null(),
0, // RuntimeLang
- unique_id)
+ unique_type_id_str)
}
})
});
- return UnfinishedMetadata {
- cache_id: cache_id_for_type(enum_type),
- metadata_stub: enum_metadata,
- llvm_type: enum_llvm_type,
- file_metadata: file_metadata,
- member_description_factory: EnumMDF(EnumMemberDescriptionFactory {
+ return create_and_register_recursive_type_forward_declaration(
+ cx,
+ enum_type,
+ unique_type_id,
+ enum_metadata,
+ enum_llvm_type,
+ file_metadata,
+ EnumMDF(EnumMemberDescriptionFactory {
+ enum_type: enum_type,
type_rep: type_rep.clone(),
variants: variants,
discriminant_type_metadata: discriminant_type_metadata,
file_metadata: file_metadata,
span: span,
}),
- };
+ );
fn get_enum_discriminant_name(cx: &CrateContext, def_id: ast::DefId) -> token::InternedString {
let name = if def_id.krate == ast::LOCAL_CRATE {
fn composite_type_metadata(cx: &CrateContext,
composite_llvm_type: Type,
composite_type_name: &str,
+ composite_type_unique_id: UniqueTypeId,
member_descriptions: &[MemberDescription],
containing_scope: DIScope,
file_metadata: DIFile,
let composite_type_metadata = create_struct_stub(cx,
composite_llvm_type,
composite_type_name,
+ composite_type_unique_id,
containing_scope,
file_metadata,
definition_span);
-
// ... and immediately create and add the member descriptions.
set_members_of_composite_type(cx,
composite_type_metadata,
let mut composite_types_completed =
debug_context(cx).composite_types_completed.borrow_mut();
if composite_types_completed.contains(&composite_type_metadata) {
- cx.sess().span_bug(definition_span, "debuginfo::set_members_of_composite_type() - \
- Already completed forward declaration \
- re-encountered.");
+ let (llvm_version_major, llvm_version_minor) = unsafe {
+ (llvm::LLVMVersionMajor(), llvm::LLVMVersionMinor())
+ };
+
+ let actual_llvm_version = llvm_version_major * 1000000 + llvm_version_minor * 1000;
+ let min_supported_llvm_version = 3 * 1000000 + 4 * 1000;
+
+ if actual_llvm_version < min_supported_llvm_version {
+ cx.sess().warn(format!("This version of rustc was built with LLVM {}.{}. \
+ Rustc just ran into a known debuginfo corruption problem that \
+ often occurs with LLVM versions below 3.4. Please use a rustc built with a \
+ newer version of LLVM.", llvm_version_major, llvm_version_minor).as_slice());
+ } else {
+ cx.sess().bug("debuginfo::set_members_of_composite_type() - \
+ Already completed forward declaration re-encountered.");
+ }
} else {
composite_types_completed.insert(composite_type_metadata);
}
fn create_struct_stub(cx: &CrateContext,
struct_llvm_type: Type,
struct_type_name: &str,
+ unique_type_id: UniqueTypeId,
containing_scope: DIScope,
file_metadata: DIFile,
definition_span: Span)
let loc = span_start(cx, definition_span);
let (struct_size, struct_align) = size_and_align_of(cx, struct_llvm_type);
- // We assign unique IDs to the type stubs so LLVM metadata uniquing does not reuse instances
- // where we don't want it.
- let unique_id = generate_unique_type_id("DI_STRUCT_");
-
- return unsafe {
+ let unique_type_id_str = debug_context(cx).type_map
+ .borrow()
+ .get_unique_type_id_as_string(unique_type_id);
+ let metadata_stub = unsafe {
struct_type_name.with_c_str(|name| {
- unique_id.as_slice().with_c_str(|unique_id| {
+ unique_type_id_str.as_slice().with_c_str(|unique_type_id| {
// LLVMDIBuilderCreateStructType() wants an empty array. A null pointer will lead to
// hard to trace and debug LLVM assertions later on in llvm/lib/IR/Value.cpp
let empty_array = create_DIArray(DIB(cx), []);
empty_array,
0,
ptr::null(),
- unique_id)
+ unique_type_id)
})
})
};
+
+ return metadata_stub;
}
-fn boxed_type_metadata(cx: &CrateContext,
- content_type_name: Option<&str>,
- content_llvm_type: Type,
- content_type_metadata: DIType,
- span: Span)
- -> DICompositeType {
- let box_type_name = match content_type_name {
- Some(content_type_name) => format!("Boxed<{}>", content_type_name),
- None => "BoxedType".to_string()
- };
+fn at_box_metadata(cx: &CrateContext,
+ content_type: ty::t,
+ unique_type_id: UniqueTypeId) -> DIType {
+ let content_type_name = ppaux::ty_to_str(cx.tcx(), content_type);
+ let content_type_name = content_type_name.as_slice();
+ let content_llvm_type = type_of::type_of(cx, content_type);
+ let content_type_metadata = type_metadata(cx, content_type, codemap::DUMMY_SP);
+ let box_type_name = format!("Boxed<{}>", content_type_name);
let box_llvm_type = Type::at_box(cx, content_llvm_type);
let member_llvm_types = box_llvm_type.field_types();
assert!(box_layout_is_correct(cx,
}
];
- let loc = span_start(cx, span);
+ let loc = span_start(cx, codemap::DUMMY_SP);
let file_metadata = file_metadata(cx, loc.file.name.as_slice());
return composite_type_metadata(
cx,
box_llvm_type,
box_type_name.as_slice(),
+ unique_type_id,
member_descriptions,
file_metadata,
file_metadata,
- span);
+ codemap::DUMMY_SP);
// Unfortunately, we cannot assert anything but the correct types here---and not whether the
// 'next' and 'prev' pointers are in the correct order.
}
}
+
fn fixed_vec_metadata(cx: &CrateContext,
element_type: ty::t,
len: uint,
};
}
-fn vec_metadata(cx: &CrateContext,
- element_type: ty::t,
- span: Span)
- -> DICompositeType {
+fn heap_vec_metadata(cx: &CrateContext,
+ vec_type: ty::t,
+ element_type: ty::t,
+ unique_type_id: UniqueTypeId,
+ span: Span)
+ -> DICompositeType {
let element_type_metadata = type_metadata(cx, element_type, span);
let element_llvm_type = type_of::type_of(cx, element_type);
let (element_size, element_align) = size_and_align_of(cx, element_llvm_type);
let vec_llvm_type = Type::vec(cx, &element_llvm_type);
- let vec_type_name = format!("[{}]",
- ppaux::ty_to_str(cx.tcx(), element_type));
+ let vec_type_name = ppaux::ty_to_str(cx.tcx(), vec_type);
let vec_type_name = vec_type_name.as_slice();
let member_llvm_types = vec_llvm_type.field_types();
cx,
vec_llvm_type,
vec_type_name,
+ unique_type_id,
member_descriptions,
file_metadata,
file_metadata,
fn vec_slice_metadata(cx: &CrateContext,
vec_type: ty::t,
element_type: ty::t,
+ unique_type_id: UniqueTypeId,
span: Span)
-> DICompositeType {
cx,
slice_llvm_type,
slice_type_name.as_slice(),
+ unique_type_id,
member_descriptions,
file_metadata,
file_metadata,
let loc = span_start(cx, span);
let file_metadata = file_metadata(cx, loc.file.name.as_slice());
- let mut signature_metadata: Vec<DIType> =
- Vec::with_capacity(signature.inputs.len() + 1);
+ let mut signature_metadata: Vec<DIType> = Vec::with_capacity(signature.inputs.len() + 1);
// return type
signature_metadata.push(match ty::get(signature.output).sty {
trait_type: ty::t,
substs: &subst::Substs,
trait_store: ty::TraitStore,
- _: &ty::BuiltinBounds)
+ _: &ty::BuiltinBounds,
+ unique_type_id: UniqueTypeId)
-> DIType {
// The implementation provided here is a stub. It makes sure that the trait type is
// assigned the correct name, size, namespace, and source location. But it does not describe
composite_type_metadata(cx,
trait_llvm_type,
name.as_slice(),
+ unique_type_id,
[],
containing_scope,
file_metadata,
definition_span)
}
+
fn type_metadata(cx: &CrateContext,
t: ty::t,
usage_site_span: Span)
-> DIType {
- let cache_id = cache_id_for_type(t);
-
- match debug_context(cx).created_types.borrow().find(&cache_id) {
- Some(type_metadata) => return *type_metadata,
- None => ()
- }
-
- fn create_pointer_to_box_metadata(cx: &CrateContext,
- pointer_type: ty::t,
- type_in_box: ty::t)
- -> DIType {
- let content_type_name = ppaux::ty_to_str(cx.tcx(), type_in_box);
- let content_type_name = content_type_name.as_slice();
- let content_llvm_type = type_of::type_of(cx, type_in_box);
- let content_type_metadata = type_metadata(
- cx,
- type_in_box,
- codemap::DUMMY_SP);
-
- let box_metadata = boxed_type_metadata(
- cx,
- Some(content_type_name),
- content_llvm_type,
- content_type_metadata,
- codemap::DUMMY_SP);
-
- pointer_type_metadata(cx, pointer_type, box_metadata)
- }
+ // Get the unique type id of this type.
+ let unique_type_id = {
+ let mut type_map = debug_context(cx).type_map.borrow_mut();
+ match type_map.find_metadata_for_type(t) {
+ Some(metadata) => {
+ return metadata;
+ },
+ None => {
+ let unique_type_id = type_map.get_unique_type_id_of_type(cx, t);
+ match type_map.find_metadata_for_unique_id(unique_type_id) {
+ Some(metadata) => {
+ type_map.register_type_with_metadata(cx, t, metadata);
+ return metadata;
+ },
+ None => {
+ // There really is no type metadata for this type, so proceed by creating
+ // it
+ unique_type_id
+ }
+ }
+ }
+ }
+ };
debug!("type_metadata: {:?}", ty::get(t));
+ macro_rules! return_if_created_in_meantime(
+ () => (
+ match debug_context(cx).type_map.borrow().find_metadata_for_unique_id(unique_type_id) {
+ Some(metadata) => return metadata,
+ None => { /* proceed normally */ }
+ };
+ )
+ )
+
let sty = &ty::get(t).sty;
- let type_metadata = match *sty {
+ let (type_metadata, should_already_be_stored_in_typemap) = match *sty {
ty::ty_nil |
ty::ty_bot |
ty::ty_bool |
ty::ty_int(_) |
ty::ty_uint(_) |
ty::ty_float(_) => {
- basic_type_metadata(cx, t)
+ (basic_type_metadata(cx, t), false)
}
ty::ty_enum(def_id, _) => {
- prepare_enum_metadata(cx, t, def_id, usage_site_span).finalize(cx)
+ let is_c_style_enum = match *adt::represent_type(cx, t) {
+ adt::CEnum(..) => true,
+ _ => false
+ };
+
+ (prepare_enum_metadata(cx, t, def_id, unique_type_id, usage_site_span).finalize(cx),
+ !is_c_style_enum)
+ }
+ ty::ty_box(pointee_type) => {
+ let box_content_metadata = at_box_metadata(cx, pointee_type, unique_type_id);
+ return_if_created_in_meantime!();
+ (pointer_type_metadata(cx, t, box_content_metadata), false)
}
- ty::ty_box(typ) => {
- create_pointer_to_box_metadata(cx, t, typ)
+ ty::ty_vec(ref mt, Some(len)) => {
+ (fixed_vec_metadata(cx, mt.ty, len, usage_site_span), false)
}
- ty::ty_vec(ref mt, Some(len)) => fixed_vec_metadata(cx, mt.ty, len, usage_site_span),
- ty::ty_uniq(typ) => {
- match ty::get(typ).sty {
+ ty::ty_uniq(pointee_type) => {
+ (match ty::get(pointee_type).sty {
ty::ty_vec(ref mt, None) => {
- let vec_metadata = vec_metadata(cx, mt.ty, usage_site_span);
+ let vec_metadata = heap_vec_metadata(cx,
+ pointee_type,
+ mt.ty,
+ unique_type_id,
+ usage_site_span);
+ return_if_created_in_meantime!();
pointer_type_metadata(cx, t, vec_metadata)
}
ty::ty_str => {
let i8_t = ty::mk_i8();
- let vec_metadata = vec_metadata(cx, i8_t, usage_site_span);
+ let vec_metadata = heap_vec_metadata(cx,
+ pointee_type,
+ i8_t,
+ unique_type_id,
+ usage_site_span);
pointer_type_metadata(cx, t, vec_metadata)
}
_ => {
- let pointee = type_metadata(cx, typ, usage_site_span);
- pointer_type_metadata(cx, t, pointee)
+ let pointee_metadata = type_metadata(cx, pointee_type, usage_site_span);
+ return_if_created_in_meantime!();
+ pointer_type_metadata(cx, t, pointee_metadata)
}
- }
+ }, false)
}
ty::ty_ptr(ref mt) | ty::ty_rptr(_, ref mt) => {
- match ty::get(mt.ty).sty {
- ty::ty_vec(ref mt, None) => vec_slice_metadata(cx, t, mt.ty, usage_site_span),
+ (match ty::get(mt.ty).sty {
+ ty::ty_vec(ref mt, None) => {
+ vec_slice_metadata(cx, t, mt.ty, unique_type_id, usage_site_span)
+ }
ty::ty_str => {
let i8_t = ty::mk_i8();
- vec_slice_metadata(cx, t, i8_t, usage_site_span)
+ vec_slice_metadata(cx, t, i8_t, unique_type_id, usage_site_span)
}
_ => {
let pointee = type_metadata(cx, mt.ty, usage_site_span);
+ return_if_created_in_meantime!();
pointer_type_metadata(cx, t, pointee)
}
- }
+ }, false)
}
ty::ty_bare_fn(ref barefnty) => {
- subroutine_type_metadata(cx, &barefnty.sig, usage_site_span)
+ (subroutine_type_metadata(cx, &barefnty.sig, usage_site_span), false)
}
ty::ty_closure(ref closurety) => {
- subroutine_type_metadata(cx, &closurety.sig, usage_site_span)
+ (subroutine_type_metadata(cx, &closurety.sig, usage_site_span), false)
}
ty::ty_trait(box ty::TyTrait {
def_id,
store,
ref bounds
}) => {
- trait_metadata(cx, def_id, t, substs, store, bounds)
+ (trait_metadata(cx, def_id, t, substs, store, bounds, unique_type_id), false)
}
ty::ty_struct(def_id, ref substs) => {
- prepare_struct_metadata(cx, t, def_id, substs, usage_site_span).finalize(cx)
+ let struct_metadata = prepare_struct_metadata(cx,
+ t,
+ def_id,
+ substs,
+ unique_type_id,
+ usage_site_span).finalize(cx);
+ (struct_metadata, true)
}
ty::ty_tup(ref elements) => {
- prepare_tuple_metadata(cx,
- t,
- elements.as_slice(),
- usage_site_span).finalize(cx)
+ let tuple_metadata = prepare_tuple_metadata(cx,
+ t,
+ elements.as_slice(),
+ unique_type_id,
+ usage_site_span).finalize(cx);
+ (tuple_metadata, true)
}
_ => {
- cx.sess().bug(format!("debuginfo: unexpected type in \
- type_metadata: {:?}",
+ cx.sess().bug(format!("debuginfo: unexpected type in type_metadata: {:?}",
sty).as_slice())
}
};
- debug_context(cx).created_types.borrow_mut().insert(cache_id, type_metadata);
+ {
+ let mut type_map = debug_context(cx).type_map.borrow_mut();
+
+ if should_already_be_stored_in_typemap {
+ // Make sure that we already have a TypeMap entry entry for the ty::t.
+ if type_map.find_metadata_for_type(t).is_none() {
+ let unique_type_id_str = type_map.get_unique_type_id_as_string(unique_type_id);
+ let error_message = format!("Expected type metadata for ty::t '{}' to already be in
+ the TypeMap but it was not (unique type id = {})",
+ ppaux::ty_to_str(cx.tcx(), t),
+ unique_type_id_str.as_slice());
+ cx.sess().span_bug(usage_site_span, error_message.as_slice());
+ }
+
+ // Also make sure that we already have a TypeMap entry entry for the unique type id.
+ if type_map.find_metadata_for_unique_id(unique_type_id).is_none() {
+ let unique_type_id_str = type_map.get_unique_type_id_as_string(unique_type_id);
+ let error_message = format!("Expected type metadata for unique type id '{}' to
+ already be in the TypeMap but it was not. (ty::t = {})",
+ unique_type_id_str.as_slice(),
+ ppaux::ty_to_str(cx.tcx(), t));
+ cx.sess().span_bug(usage_site_span, error_message.as_slice());
+ }
+ } else {
+ type_map.register_type_with_metadata(cx, t, type_metadata);
+ type_map.register_unique_id_with_metadata(cx, unique_type_id, type_metadata);
+ }
+ }
+
type_metadata
}
// Utility Functions
//=-------------------------------------------------------------------------------------------------
-fn cache_id_for_type(t: ty::t) -> uint {
- ty::type_id(t)
-}
-
-// Used to avoid LLVM metadata uniquing problems. See `create_struct_stub()` and
-// `prepare_enum_metadata()`.
-fn generate_unique_type_id(prefix: &'static str) -> String {
- unsafe {
- static mut unique_id_counter: atomics::AtomicUint = atomics::INIT_ATOMIC_UINT;
- format!("{}{}", prefix,
- unique_id_counter.fetch_add(1, atomics::SeqCst))
- }
-}
-
/// Return codemap::Loc corresponding to the beginning of the span
fn span_start(cx: &CrateContext, span: Span) -> codemap::Loc {
cx.sess().codemap().lookup_char_pos(span.lo)
}
}
+/// If the given def ID describes a method belonging to an impl, return the
+/// ID of the impl that the method belongs to. Otherwise, return `None`.
+pub fn impl_of_method(tcx: &ctxt, def_id: ast::DefId)
+ -> Option<ast::DefId> {
+ if def_id.krate != LOCAL_CRATE {
+ return match csearch::get_method(tcx, def_id).container {
+ TraitContainer(_) => None,
+ ImplContainer(def_id) => Some(def_id),
+ };
+ }
+ match tcx.methods.borrow().find_copy(&def_id) {
+ Some(method) => {
+ match method.container {
+ TraitContainer(_) => None,
+ ImplContainer(def_id) => Some(def_id),
+ }
+ }
+ None => None
+ }
+}
+
/// If the given def ID describes a method belonging to a trait (either a
/// default method or an implementation of a trait method), return the ID of
/// the trait that the method belongs to. Otherwise, return `None`.
```rust
local_data_key!(key_int: int)
-local_data_key!(key_vector: ~[int])
+local_data_key!(key_vector: Vec<int>)
key_int.replace(Some(3));
assert_eq!(*key_int.get().unwrap(), 3);
-key_vector.replace(Some(~[4]));
-assert_eq!(*key_vector.get().unwrap(), ~[4]);
+key_vector.replace(Some(vec![4]));
+assert_eq!(*key_vector.get().unwrap(), vec![4]);
```
*/
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/")]
-#![deny(deprecated_owned_vector)]
use std::char;
use std::cmp;
```
Two wrapper functions are provided to encode a Encodable object
-into a string (String) or buffer (~[u8]): `str_encode(&m)` and `buffer_encode(&m)`.
+into a string (String) or buffer (vec![u8]): `str_encode(&m)` and `buffer_encode(&m)`.
```rust
use serialize::json;
fn to_json(&self) -> Json { List(self.iter().map(|elt| elt.to_json()).collect()) }
}
-impl<A:ToJson> ToJson for ~[A] {
- fn to_json(&self) -> Json { List(self.iter().map(|elt| elt.to_json()).collect()) }
-}
-
impl<A:ToJson> ToJson for Vec<A> {
fn to_json(&self) -> Json { List(self.iter().map(|elt| elt.to_json()).collect()) }
}
let _hm: HashMap<uint, bool> = Decodable::decode(&mut decoder).unwrap();
}
- fn assert_stream_equal(src: &str, expected: ~[(JsonEvent, ~[StackElement])]) {
+ fn assert_stream_equal(src: &str,
+ expected: Vec<(JsonEvent, Vec<StackElement>)>) {
let mut parser = Parser::new(src.chars());
let mut i = 0;
loop {
Some(e) => e,
None => { break; }
};
- let (ref expected_evt, ref expected_stack) = expected[i];
+ let (ref expected_evt, ref expected_stack) = *expected.get(i);
if !parser.stack().is_equal_to(expected_stack.as_slice()) {
fail!("Parser stack is not equal to {}", expected_stack);
}
}
}
#[test]
+ #[ignore(cfg(target_word_size = "32"))] // FIXME(#14064)
fn test_streaming_parser() {
assert_stream_equal(
r#"{ "foo":"bar", "array" : [0, 1, 2,3 ,4,5], "idents":[null,true,false]}"#,
- ~[
- (ObjectStart, ~[]),
- (StringValue("bar".to_string()), ~[Key("foo")]),
- (ListStart, ~[Key("array")]),
- (NumberValue(0.0), ~[Key("array"), Index(0)]),
- (NumberValue(1.0), ~[Key("array"), Index(1)]),
- (NumberValue(2.0), ~[Key("array"), Index(2)]),
- (NumberValue(3.0), ~[Key("array"), Index(3)]),
- (NumberValue(4.0), ~[Key("array"), Index(4)]),
- (NumberValue(5.0), ~[Key("array"), Index(5)]),
- (ListEnd, ~[Key("array")]),
- (ListStart, ~[Key("idents")]),
- (NullValue, ~[Key("idents"), Index(0)]),
- (BooleanValue(true), ~[Key("idents"), Index(1)]),
- (BooleanValue(false), ~[Key("idents"), Index(2)]),
- (ListEnd, ~[Key("idents")]),
- (ObjectEnd, ~[]),
+ vec![
+ (ObjectStart, vec![]),
+ (StringValue("bar".to_string()), vec![Key("foo")]),
+ (ListStart, vec![Key("array")]),
+ (NumberValue(0.0), vec![Key("array"), Index(0)]),
+ (NumberValue(1.0), vec![Key("array"), Index(1)]),
+ (NumberValue(2.0), vec![Key("array"), Index(2)]),
+ (NumberValue(3.0), vec![Key("array"), Index(3)]),
+ (NumberValue(4.0), vec![Key("array"), Index(4)]),
+ (NumberValue(5.0), vec![Key("array"), Index(5)]),
+ (ListEnd, vec![Key("array")]),
+ (ListStart, vec![Key("idents")]),
+ (NullValue, vec![Key("idents"), Index(0)]),
+ (BooleanValue(true), vec![Key("idents"), Index(1)]),
+ (BooleanValue(false), vec![Key("idents"), Index(2)]),
+ (ListEnd, vec![Key("idents")]),
+ (ObjectEnd, vec![]),
]
);
}
assert_stream_equal(
"{}",
- box [(ObjectStart, box []), (ObjectEnd, box [])]
+ vec![(ObjectStart, vec![]), (ObjectEnd, vec![])]
);
assert_stream_equal(
"{\"a\": 3}",
- box [
- (ObjectStart, box []),
- (NumberValue(3.0), box [Key("a")]),
- (ObjectEnd, box []),
+ vec![
+ (ObjectStart, vec![]),
+ (NumberValue(3.0), vec![Key("a")]),
+ (ObjectEnd, vec![]),
]
);
assert_stream_equal(
"{ \"a\": null, \"b\" : true }",
- box [
- (ObjectStart, box []),
- (NullValue, box [Key("a")]),
- (BooleanValue(true), box [Key("b")]),
- (ObjectEnd, box []),
+ vec![
+ (ObjectStart, vec![]),
+ (NullValue, vec![Key("a")]),
+ (BooleanValue(true), vec![Key("b")]),
+ (ObjectEnd, vec![]),
]
);
assert_stream_equal(
"{\"a\" : 1.0 ,\"b\": [ true ]}",
- box [
- (ObjectStart, box []),
- (NumberValue(1.0), box [Key("a")]),
- (ListStart, box [Key("b")]),
- (BooleanValue(true),box [Key("b"), Index(0)]),
- (ListEnd, box [Key("b")]),
- (ObjectEnd, box []),
+ vec![
+ (ObjectStart, vec![]),
+ (NumberValue(1.0), vec![Key("a")]),
+ (ListStart, vec![Key("b")]),
+ (BooleanValue(true),vec![Key("b"), Index(0)]),
+ (ListEnd, vec![Key("b")]),
+ (ObjectEnd, vec![]),
]
);
assert_stream_equal(
{ "c": {"d": null} }
]
}"#,
- ~[
- (ObjectStart, ~[]),
- (NumberValue(1.0), ~[Key("a")]),
- (ListStart, ~[Key("b")]),
- (BooleanValue(true), ~[Key("b"), Index(0)]),
- (StringValue("foo\nbar".to_string()), ~[Key("b"), Index(1)]),
- (ObjectStart, ~[Key("b"), Index(2)]),
- (ObjectStart, ~[Key("b"), Index(2), Key("c")]),
- (NullValue, ~[Key("b"), Index(2), Key("c"), Key("d")]),
- (ObjectEnd, ~[Key("b"), Index(2), Key("c")]),
- (ObjectEnd, ~[Key("b"), Index(2)]),
- (ListEnd, ~[Key("b")]),
- (ObjectEnd, ~[]),
+ vec![
+ (ObjectStart, vec![]),
+ (NumberValue(1.0), vec![Key("a")]),
+ (ListStart, vec![Key("b")]),
+ (BooleanValue(true), vec![Key("b"), Index(0)]),
+ (StringValue("foo\nbar".to_string()), vec![Key("b"), Index(1)]),
+ (ObjectStart, vec![Key("b"), Index(2)]),
+ (ObjectStart, vec![Key("b"), Index(2), Key("c")]),
+ (NullValue, vec![Key("b"), Index(2), Key("c"), Key("d")]),
+ (ObjectEnd, vec![Key("b"), Index(2), Key("c")]),
+ (ObjectEnd, vec![Key("b"), Index(2)]),
+ (ListEnd, vec![Key("b")]),
+ (ObjectEnd, vec![]),
]
);
}
fn test_read_list_streaming() {
assert_stream_equal(
"[]",
- box [
- (ListStart, box []),
- (ListEnd, box []),
+ vec![
+ (ListStart, vec![]),
+ (ListEnd, vec![]),
]
);
assert_stream_equal(
"[ ]",
- box [
- (ListStart, box []),
- (ListEnd, box []),
+ vec![
+ (ListStart, vec![]),
+ (ListEnd, vec![]),
]
);
assert_stream_equal(
"[true]",
- box [
- (ListStart, box []),
- (BooleanValue(true), box [Index(0)]),
- (ListEnd, box []),
+ vec![
+ (ListStart, vec![]),
+ (BooleanValue(true), vec![Index(0)]),
+ (ListEnd, vec![]),
]
);
assert_stream_equal(
"[ false ]",
- box [
- (ListStart, box []),
- (BooleanValue(false), box [Index(0)]),
- (ListEnd, box []),
+ vec![
+ (ListStart, vec![]),
+ (BooleanValue(false), vec![Index(0)]),
+ (ListEnd, vec![]),
]
);
assert_stream_equal(
"[null]",
- box [
- (ListStart, box []),
- (NullValue, box [Index(0)]),
- (ListEnd, box []),
+ vec![
+ (ListStart, vec![]),
+ (NullValue, vec![Index(0)]),
+ (ListEnd, vec![]),
]
);
assert_stream_equal(
"[3, 1]",
- box [
- (ListStart, box []),
- (NumberValue(3.0), box [Index(0)]),
- (NumberValue(1.0), box [Index(1)]),
- (ListEnd, box []),
+ vec![
+ (ListStart, vec![]),
+ (NumberValue(3.0), vec![Index(0)]),
+ (NumberValue(1.0), vec![Index(1)]),
+ (ListEnd, vec![]),
]
);
assert_stream_equal(
"\n[3, 2]\n",
- box [
- (ListStart, box []),
- (NumberValue(3.0), box [Index(0)]),
- (NumberValue(2.0), box [Index(1)]),
- (ListEnd, box []),
+ vec![
+ (ListStart, vec![]),
+ (NumberValue(3.0), vec![Index(0)]),
+ (NumberValue(2.0), vec![Index(1)]),
+ (ListEnd, vec![]),
]
);
assert_stream_equal(
"[2, [4, 1]]",
- box [
- (ListStart, box []),
- (NumberValue(2.0), box [Index(0)]),
- (ListStart, box [Index(1)]),
- (NumberValue(4.0), box [Index(1), Index(0)]),
- (NumberValue(1.0), box [Index(1), Index(1)]),
- (ListEnd, box [Index(1)]),
- (ListEnd, box []),
+ vec![
+ (ListStart, vec![]),
+ (NumberValue(2.0), vec![Index(0)]),
+ (ListStart, vec![Index(1)]),
+ (NumberValue(4.0), vec![Index(1), Index(0)]),
+ (NumberValue(1.0), vec![Index(1), Index(1)]),
+ (ListEnd, vec![Index(1)]),
+ (ListEnd, vec![]),
]
);
assert_eq!((1, 2, 3).to_json(), list3);
assert_eq!([1, 2].to_json(), list2);
assert_eq!((&[1, 2, 3]).to_json(), list3);
- assert_eq!((~[1, 2]).to_json(), list2);
+ assert_eq!((vec![1, 2]).to_json(), list2);
assert_eq!(vec!(1, 2, 3).to_json(), list3);
let mut tree_map = TreeMap::new();
tree_map.insert("a".to_string(), 1);
}
}
-impl<E, S:Encoder<E>,T:Encodable<S, E>> Encodable<S, E> for ~[T] {
- fn encode(&self, s: &mut S) -> Result<(), E> {
- s.emit_seq(self.len(), |s| {
- for (i, e) in self.iter().enumerate() {
- try!(s.emit_seq_elt(i, |s| e.encode(s)))
- }
- Ok(())
- })
- }
-}
-
-impl<E, D:Decoder<E>,T:Decodable<D, E>> Decodable<D, E> for ~[T] {
- fn decode(d: &mut D) -> Result<~[T], E> {
- use std::vec::FromVec;
-
- d.read_seq(|d, len| {
- let mut v: Vec<T> = Vec::with_capacity(len);
- for i in range(0, len) {
- v.push(try!(d.read_seq_elt(i, |d| Decodable::decode(d))));
- }
- let k: ~[T] = FromVec::from_vec(v);
- Ok(k)
- })
- }
-}
-
impl<E, S:Encoder<E>,T:Encodable<S, E>> Encodable<S, E> for Vec<T> {
fn encode(&self, s: &mut S) -> Result<(), E> {
s.emit_seq(self.len(), |s| {
unsafe fn into_ascii_nocheck(self) -> Vec<Ascii>;
}
-impl OwnedAsciiCast for ~[u8] {
- #[inline]
- fn is_ascii(&self) -> bool {
- self.as_slice().is_ascii()
- }
-
- #[inline]
- unsafe fn into_ascii_nocheck(self) -> Vec<Ascii> {
- mem::transmute(Vec::from_slice(self.as_slice()))
- }
-}
-
impl OwnedAsciiCast for String {
#[inline]
fn is_ascii(&self) -> bool {
}
}
-impl IntoStr for ~[Ascii] {
- #[inline]
- fn into_str(self) -> String {
- let vector: Vec<Ascii> = self.as_slice().iter().map(|x| *x).collect();
- vector.into_str()
- }
-}
-
impl IntoStr for Vec<Ascii> {
#[inline]
fn into_str(self) -> String {
let test = &[40u8, 32u8, 59u8];
assert_eq!(test.to_ascii(), v2ascii!([40, 32, 59]));
assert_eq!("( ;".to_ascii(), v2ascii!([40, 32, 59]));
- let v = box [40u8, 32u8, 59u8];
- assert_eq!(v.to_ascii(), v2ascii!([40, 32, 59]));
+ let v = vec![40u8, 32u8, 59u8];
+ assert_eq!(v.as_slice().to_ascii(), v2ascii!([40, 32, 59]));
assert_eq!("( ;".to_string().as_slice().to_ascii(), v2ascii!([40, 32, 59]));
assert_eq!("abCDef&?#".to_ascii().to_lower().into_str(), "abcdef&?#".to_string());
#[test]
fn test_owned_ascii_vec() {
assert_eq!(("( ;".to_string()).into_ascii(), vec2ascii![40, 32, 59]);
- assert_eq!((box [40u8, 32u8, 59u8]).into_ascii(), vec2ascii![40, 32, 59]);
+ assert_eq!((vec![40u8, 32u8, 59u8]).into_ascii(), vec2ascii![40, 32, 59]);
}
#[test]
use io;
use option::{None, Option, Some};
use result::{Ok, Err};
-use super::{Reader, Writer, IoResult};
-use str::StrSlice;
use slice::{bytes, MutableVector, ImmutableVector};
+use str::StrSlice;
+use super::{Reader, Writer, IoResult};
use vec::Vec;
/// Allows reading from a rx.
assert_eq!(Ok(2), reader.read(buf));
assert_eq!(&[7,8,6], buf.as_slice());
- match reader.read(buf) {
+ match reader.read(buf.as_mut_slice()) {
Ok(..) => fail!(),
Err(e) => assert_eq!(e.kind, io::EndOfFile),
}
assert_eq!(&[7,8,6], buf.as_slice());
// Ensure it continues to fail in the same way.
- match reader.read(buf) {
+ match reader.read(buf.as_mut_slice()) {
Ok(..) => fail!(),
Err(e) => assert_eq!(e.kind, io::EndOfFile),
}
#[test]
fn test_read_f32() {
//big-endian floating-point 8.1250
- let buf = box [0x41, 0x02, 0x00, 0x00];
+ let buf = vec![0x41, 0x02, 0x00, 0x00];
let mut writer = MemWriter::new();
- writer.write(buf).unwrap();
+ writer.write(buf.as_slice()).unwrap();
let mut reader = MemReader::new(writer.unwrap());
let f = reader.read_be_f32().unwrap();
use c_str::ToCStr;
use clone::Clone;
use collections::Collection;
+use io::{FilePermission, Write, UnstableFileStat, Open, FileAccess, FileMode};
+use io::{IoResult, IoError, FileStat, SeekStyle, Seek, Writer, Reader};
+use io::{Read, Truncate, SeekCur, SeekSet, ReadWrite, SeekEnd, Append};
use io;
use iter::Iterator;
use kinds::Send;
use owned::Box;
use path::{Path, GenericPath};
use path;
-use result::{Ok, Err};
-use rt::rtio::{RtioFileStream, IoFactory, LocalIo};
+use result::{Err, Ok};
+use rt::rtio::LocalIo;
use rt::rtio;
-use slice::{OwnedVector, ImmutableVector};
-use super::UnstableFileStat;
-use super::{FileMode, FileAccess, FileStat, IoResult, FilePermission};
-use super::{Reader, Writer, Seek, Append, SeekCur, SeekEnd, SeekSet};
-use super::{SeekStyle, Read, Write, ReadWrite, Open, IoError, Truncate};
+use slice::ImmutableVector;
use vec::Vec;
/// Unconstrained file access type that exposes read and write operations
/// configured at creation time, via the `FileAccess` parameter to
/// `File::open_mode()`.
pub struct File {
- fd: Box<RtioFileStream:Send>,
+ fd: Box<rtio::RtioFileStream:Send>,
path: Path,
last_nread: int,
}
let mut read_buf = [0, .. 1028];
let read_str = match check!(read_stream.read(read_buf)) {
-1|0 => fail!("shouldn't happen"),
- n => str::from_utf8(read_buf.slice_to(n).to_owned()).unwrap().to_owned()
+ n => str::from_utf8(read_buf.slice_to(n)).unwrap().to_owned()
};
assert_eq!(read_str, message.to_owned());
}
#[test]
fn test_buf_reader() {
- let in_buf = box [0, 1, 2, 3, 4, 5, 6, 7];
- let mut reader = BufReader::new(in_buf);
+ let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7];
+ let mut reader = BufReader::new(in_buf.as_slice());
let mut buf = [];
assert_eq!(reader.read(buf), Ok(0));
assert_eq!(reader.tell(), Ok(0));
assert_eq!(reader.read(buf), Ok(3));
assert_eq!(buf.slice(0, 3), &[5, 6, 7]);
assert!(reader.read(buf).is_err());
- let mut reader = BufReader::new(in_buf);
+ let mut reader = BufReader::new(in_buf.as_slice());
assert_eq!(reader.read_until(3).unwrap(), vec!(0, 1, 2, 3));
assert_eq!(reader.read_until(3).unwrap(), vec!(4, 5, 6, 7));
assert!(reader.read(buf).is_err());
})
iotest!(fn test_add_to_env() {
- let new_env = box [("RUN_TEST_NEW_ENV", "123")];
- let prog = env_cmd().env(new_env).spawn().unwrap();
+ let new_env = vec![("RUN_TEST_NEW_ENV", "123")];
+ let prog = env_cmd().env(new_env.as_slice()).spawn().unwrap();
let result = prog.wait_with_output().unwrap();
let output = str::from_utf8_lossy(result.output.as_slice()).into_string();
#[test]
fn test_null_writer() {
let mut s = NullWriter;
- let buf = box [0, 0, 0];
- s.write(buf).unwrap();
+ let buf = vec![0, 0, 0];
+ s.write(buf.as_slice()).unwrap();
s.flush().unwrap();
}
#[test]
fn test_zero_reader() {
let mut s = ZeroReader;
- let mut buf = box [1, 2, 3];
- assert_eq!(s.read(buf), Ok(3));
- assert_eq!(box [0, 0, 0], buf);
+ let mut buf = vec![1, 2, 3];
+ assert_eq!(s.read(buf.as_mut_slice()), Ok(3));
+ assert_eq!(vec![0, 0, 0], buf);
}
#[test]
fn test_null_reader() {
let mut r = NullReader;
- let mut buf = box [0];
- assert!(r.read(buf).is_err());
+ let mut buf = vec![0];
+ assert!(r.read(buf.as_mut_slice()).is_err());
}
#[test]
use ptr::RawPtr;
use ptr;
use result::{Err, Ok, Result};
-use slice::{Vector, ImmutableVector, MutableVector, OwnedVector};
+use slice::{Vector, ImmutableVector, MutableVector};
use str::{Str, StrSlice, StrAllocating};
use str;
use string::String;
/// # Example
///
/// ```rust
+/// use std::os;
+///
/// // We assume that we are in a valid directory like "/home".
-/// let current_working_directory = std::os::getcwd();
+/// let current_working_directory = os::getcwd();
/// println!("The current directory is {}", current_working_directory.display());
/// // /home
/// ```
/// # Example
///
/// ```rust
+/// use std::os;
+///
/// // We assume that we are in a valid directory like "C:\\Windows".
-/// let current_working_directory = std::os::getcwd();
+/// let current_working_directory = os::getcwd();
/// println!("The current directory is {}", current_working_directory.display());
/// // C:\\Windows
/// ```
}
}
-/// Returns a vector of (variable, value) pairs as a Vec<(String, String)>,
-/// for all the environment variables of the current process.
+/// Returns a vector of (variable, value) pairs, for all the environment
+/// variables of the current process.
///
/// Invalid UTF-8 bytes are replaced with \uFFFD. See `str::from_utf8_lossy()`
/// for details.
/// # Example
///
/// ```rust
-/// // We will iterate through the references to the element returned by std::os::env();
-/// for &(ref key, ref value) in std::os::env().iter() {
+/// use std::os;
+///
+/// // We will iterate through the references to the element returned by os::env();
+/// for &(ref key, ref value) in os::env().iter() {
/// println!("'{}': '{}'", key, value );
/// }
/// ```
/// # Example
///
/// ```rust
+/// use std::os;
+///
/// let key = "HOME";
-/// match std::os::getenv(key) {
+/// match os::getenv(key) {
/// Some(val) => println!("{}: {}", key, val),
/// None => println!("{} is not defined in the environment.", key)
/// }
getenv(n).map(|s| s.into_bytes())
}
-
-#[cfg(unix)]
/// Sets the environment variable `n` to the value `v` for the currently running
-/// process
+/// process.
///
-/// # Failure
+/// # Example
///
-/// Fails if `n` or `v` have any interior NULs.
+/// ```rust
+/// use std::os;
+///
+/// let key = "KEY";
+/// os::setenv(key, "VALUE");
+/// match os::getenv(key) {
+/// Some(ref val) => println!("{}: {}", key, val),
+/// None => println!("{} is not defined in the environment.", key)
+/// }
+/// ```
pub fn setenv(n: &str, v: &str) {
- unsafe {
- with_env_lock(|| {
- n.with_c_str(|nbuf| {
- v.with_c_str(|vbuf| {
- libc::funcs::posix01::unistd::setenv(nbuf, vbuf, 1);
+ #[cfg(unix)]
+ fn _setenv(n: &str, v: &str) {
+ unsafe {
+ with_env_lock(|| {
+ n.with_c_str(|nbuf| {
+ v.with_c_str(|vbuf| {
+ libc::funcs::posix01::unistd::setenv(nbuf, vbuf, 1);
+ })
})
})
- })
+ }
}
-}
-
-#[cfg(windows)]
-/// Sets the environment variable `n` to the value `v` for the currently running
-/// process
-pub fn setenv(n: &str, v: &str) {
- let n = n.to_utf16().append_one(0);
- let v = v.to_utf16().append_one(0);
- unsafe {
- with_env_lock(|| {
- libc::SetEnvironmentVariableW(n.as_ptr(), v.as_ptr());
- })
+ #[cfg(windows)]
+ fn _setenv(n: &str, v: &str) {
+ let n = n.to_utf16().append_one(0);
+ let v = v.to_utf16().append_one(0);
+ unsafe {
+ with_env_lock(|| {
+ libc::SetEnvironmentVariableW(n.as_ptr(), v.as_ptr());
+ })
+ }
}
+ _setenv(n, v)
}
-/// Remove a variable from the environment entirely
-///
-/// # Failure
-///
-/// Fails (on unix) if `n` has any interior NULs.
+/// Remove a variable from the environment entirely.
pub fn unsetenv(n: &str) {
#[cfg(unix)]
fn _unsetenv(n: &str) {
})
}
}
+
#[cfg(windows)]
fn _unsetenv(n: &str) {
let n = n.to_utf16().append_one(0);
})
}
}
-
_unsetenv(n);
}
#[cfg(unix)]
/// Parse a string or vector according to the platform's conventions
-/// for the `PATH` environment variable. Drops empty paths.
+/// for the `PATH` environment variable and return a Vec<Path>.
+/// Drops empty paths.
+///
+/// # Example
+/// ```rust
+/// use std::os;
+///
+/// let key = "PATH";
+/// match os::getenv(key) {
+/// Some(paths) => {
+/// for path in os::split_paths(paths).iter() {
+/// println!("'{}'", path.display());
+/// }
+/// }
+/// None => println!("{} is not defined in the environnement.", key)
+/// }
+/// ```
pub fn split_paths<T: BytesContainer>(unparsed: T) -> Vec<Path> {
unparsed.container_as_bytes()
.split(|b| *b == ':' as u8)
pub out: c_int,
}
-/// Creates a new low-level OS in-memory pipe.
+/// Creates a new low-level OS in-memory pipe represented as a Pipe struct.
#[cfg(unix)]
pub fn pipe() -> Pipe {
unsafe {
}
}
-/// Creates a new low-level OS in-memory pipe.
+/// Creates a new low-level OS in-memory pipe represented as a Pipe struct.
#[cfg(windows)]
pub fn pipe() -> Pipe {
unsafe {
}
}
-/// Returns the proper dll filename for the given basename of a file.
+/// Returns the proper dll filename for the given basename of a file
+/// as a String.
pub fn dll_filename(base: &str) -> String {
format!("{}{}{}", consts::DLL_PREFIX, base, consts::DLL_SUFFIX)
}
-/// Optionally returns the filesystem path of the current executable which is
-/// running. If any failure occurs, None is returned.
+/// Optionally returns the filesystem path to the current executable which is
+/// running but with the executable name.
+///
+/// # Examples
+///
+/// ```rust
+/// use std::os;
+///
+/// match os::self_exe_name() {
+/// Some(exe_path) => println!("Path of this executable is: {}", exe_path.display()),
+/// None => println!("Unable to get the path of this executable!")
+/// };
+/// ```
pub fn self_exe_name() -> Option<Path> {
#[cfg(target_os = "freebsd")]
unsafe {
use libc::funcs::bsd44::*;
use libc::consts::os::extra::*;
- let mib = box [CTL_KERN as c_int,
+ let mib = vec![CTL_KERN as c_int,
KERN_PROC as c_int,
KERN_PROC_PATHNAME as c_int, -1 as c_int];
let mut sz: libc::size_t = 0;
}
/// Optionally returns the filesystem path to the current executable which is
-/// running. Like self_exe_name() but without the binary's name.
-/// If any failure occurs, None is returned.
+/// running.
+///
+/// Like self_exe_name() but without the binary's name.
+///
+/// # Example
+///
+/// ```rust
+/// use std::os;
+///
+/// match os::self_exe_path() {
+/// Some(exe_path) => println!("Executable's Path is: {}", exe_path.display()),
+/// None => println!("Impossible to fetch the path of this executable.")
+/// };
+/// ```
pub fn self_exe_path() -> Option<Path> {
self_exe_name().map(|mut p| { p.pop(); p })
}
-/**
- * Returns the path to the user's home directory, if known.
- *
- * On Unix, returns the value of the 'HOME' environment variable if it is set
- * and not equal to the empty string.
- *
- * On Windows, returns the value of the 'HOME' environment variable if it is
- * set and not equal to the empty string. Otherwise, returns the value of the
- * 'USERPROFILE' environment variable if it is set and not equal to the empty
- * string.
- *
- * Otherwise, homedir returns option::none.
- */
+/// Optionally returns the path to the current user's home directory if known.
+///
+/// # Unix
+///
+/// Returns the value of the 'HOME' environment variable if it is set
+/// and not equal to the empty string.
+///
+/// # Windows
+///
+/// Returns the value of the 'HOME' environment variable if it is
+/// set and not equal to the empty string. Otherwise, returns the value of the
+/// 'USERPROFILE' environment variable if it is set and not equal to the empty
+/// string.
+///
+/// # Example
+///
+/// ```rust
+/// use std::os;
+///
+/// match os::homedir() {
+/// Some(ref p) => println!("{}", p.display()),
+/// None => println!("Impossible to get your home dir!")
+/// }
+/// ```
pub fn homedir() -> Option<Path> {
- // FIXME (#7188): getenv needs a Vec<u8> variant
- return match getenv("HOME") {
- Some(ref p) if !p.is_empty() => Path::new_opt(p.as_slice()),
- _ => secondary()
- };
-
+ #[inline]
#[cfg(unix)]
- fn secondary() -> Option<Path> {
- None
+ fn _homedir() -> Option<Path> {
+ aux_homedir("HOME")
}
+ #[inline]
#[cfg(windows)]
- fn secondary() -> Option<Path> {
- getenv("USERPROFILE").and_then(|p| {
- if !p.is_empty() {
- Path::new_opt(p)
- } else {
- None
- }
- })
+ fn _homedir() -> Option<Path> {
+ aux_homedir("HOME").or(aux_homedir("USERPROFILE"))
+ }
+
+ #[inline]
+ fn aux_homedir(home_name: &str) -> Option<Path> {
+ match getenv_as_bytes(home_name) {
+ Some(p) => {
+ if p.is_empty() { None } else { Path::new_opt(p) }
+ },
+ _ => None
+ }
}
+ _homedir()
}
/**
assert!(os::homedir().is_none());
for s in oldhome.iter() {
- setenv("HOME", s.as_slice())
+ setenv("HOME", s.as_slice());
}
}
assert!(os::homedir() == Some(Path::new("/home/MountainView")));
for s in oldhome.iter() {
- setenv("HOME", s.as_slice())
+ setenv("HOME", s.as_slice());
}
for s in olduserprofile.iter() {
- setenv("USERPROFILE", s.as_slice())
+ setenv("USERPROFILE", s.as_slice());
}
}
*/
-#![deny(deprecated_owned_vector)]
-
use collections::Collection;
use c_str::CString;
use clone::Clone;
}
}
-impl BytesContainer for ~[u8] {
- #[inline]
- fn container_as_bytes<'a>(&'a self) -> &'a [u8] {
- self.as_slice()
- }
-}
-
impl BytesContainer for Vec<u8> {
#[inline]
fn container_as_bytes<'a>(&'a self) -> &'a [u8] {
use str::Str;
use str;
use slice::{CloneableVector, Splits, Vector, VectorVector,
- ImmutableEqVector, OwnedVector, ImmutableVector};
+ ImmutableEqVector, ImmutableVector};
use vec::Vec;
use super::{BytesContainer, GenericPath, GenericPathUnsafe};
}
}
- #[allow(deprecated_owned_vector)]
fn path_relative_from(&self, base: &Path) -> Option<Path> {
if self.is_absolute() != base.is_absolute() {
if self.is_absolute() {
use iter::{AdditiveIterator, DoubleEndedIterator, Extendable, Iterator, Map};
use mem;
use option::{Option, Some, None};
-use slice::{Vector, OwnedVector, ImmutableVector};
+use slice::{Vector, ImmutableVector};
use str::{CharSplits, Str, StrAllocating, StrVector, StrSlice};
use string::String;
use vec::Vec;
#[doc(no_inline)] pub use slice::{MutableCloneableVector, MutableOrdVector};
#[doc(no_inline)] pub use slice::{ImmutableVector, MutableVector};
#[doc(no_inline)] pub use slice::{ImmutableEqVector, ImmutableOrdVector};
-#[doc(no_inline)] pub use slice::{Vector, VectorVector, OwnedVector};
+#[doc(no_inline)] pub use slice::{Vector, VectorVector};
#[doc(no_inline)] pub use slice::MutableVectorAllocating;
#[doc(no_inline)] pub use string::String;
#[doc(no_inline)] pub use vec::Vec;
use std::rand::Rng;
let mut rng = rand::task_rng();
-if rng.gen() { // bool
+if rng.gen() { // random bool
println!("int: {}, uint: {}", rng.gen::<int>(), rng.gen::<uint>())
}
```
}
#[cfg(test)]
-#[allow(deprecated_owned_vector)]
mod test {
use prelude::*;
#[test]
fn test_reader_rng_u64() {
// transmute from the target to avoid endianness concerns.
- let v = box [1u64, 2u64, 3u64];
- let bytes: ~[u8] = unsafe {mem::transmute(v)};
- let mut rng = ReaderRng::new(MemReader::new(bytes.move_iter().collect()));
+ let v = vec![0u8, 0, 0, 0, 0, 0, 0, 1,
+ 0 , 0, 0, 0, 0, 0, 0, 2,
+ 0, 0, 0, 0, 0, 0, 0, 3];
+ let mut rng = ReaderRng::new(MemReader::new(v));
- assert_eq!(rng.next_u64(), 1);
- assert_eq!(rng.next_u64(), 2);
- assert_eq!(rng.next_u64(), 3);
+ assert_eq!(rng.next_u64(), mem::to_be64(1));
+ assert_eq!(rng.next_u64(), mem::to_be64(2));
+ assert_eq!(rng.next_u64(), mem::to_be64(3));
}
#[test]
fn test_reader_rng_u32() {
- // transmute from the target to avoid endianness concerns.
- let v = box [1u32, 2u32, 3u32];
- let bytes: ~[u8] = unsafe {mem::transmute(v)};
- let mut rng = ReaderRng::new(MemReader::new(bytes.move_iter().collect()));
+ let v = vec![0u8, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3];
+ let mut rng = ReaderRng::new(MemReader::new(v));
- assert_eq!(rng.next_u32(), 1);
- assert_eq!(rng.next_u32(), 2);
- assert_eq!(rng.next_u32(), 3);
+ assert_eq!(rng.next_u32(), mem::to_be32(1));
+ assert_eq!(rng.next_u32(), mem::to_be32(2));
+ assert_eq!(rng.next_u32(), mem::to_be32(3));
}
#[test]
fn test_reader_rng_fill_bytes() {
#[cfg(test)]
mod tests {
+ use prelude::*;
use super::*;
- use str::StrAllocating;
#[test]
fn test_simple_types() {
#[test]
fn test_vectors() {
- let x: ~[int] = box [];
+ let x: Vec<int> = vec![];
assert_eq!(x.to_str(), "[]".to_string());
- assert_eq!((box [1]).to_str(), "[1]".to_string());
- assert_eq!((box [1, 2, 3]).to_str(), "[1, 2, 3]".to_string());
- assert!((box [box [], box [1], box [1, 1]]).to_str() ==
+ assert_eq!((vec![1]).to_str(), "[1]".to_string());
+ assert_eq!((vec![1, 2, 3]).to_str(), "[1, 2, 3]".to_string());
+ assert!((vec![vec![], vec![1], vec![1, 1]]).to_str() ==
"[[], [1], [1, 1]]".to_string());
}
}
html_root_url = "http://doc.rust-lang.org/",
html_playground_url = "http://play.rust-lang.org/")]
#![feature(phase, globs, macro_rules)]
-#![deny(deprecated_owned_vector)]
+
#![deny(missing_doc)]
#![no_std]
use mutex::{StaticMutex, MUTEX_INIT};
-/// A type which can be used to run a one-time global initialization. This type
-/// is *unsafe* to use because it is built on top of the `Mutex` in this module.
-/// It does not know whether the currently running task is in a green or native
-/// context, and a blocking mutex should *not* be used under normal
-/// circumstances on a green task.
-///
-/// Despite its unsafety, it is often useful to have a one-time initialization
-/// routine run for FFI bindings or related external functionality. This type
-/// can only be statically constructed with the `ONCE_INIT` value.
+/// A synchronization primitive which can be used to run a one-time global
+/// initialization. Useful for one-time initialization for FFI or related
+/// functionality. This type can only be constructed with the `ONCE_INIT`
+/// value.
///
/// # Example
///
/// use sync::one::{Once, ONCE_INIT};
///
/// static mut START: Once = ONCE_INIT;
+///
/// unsafe {
/// START.doit(|| {
/// // run initialization here
/// will be executed if this is the first time `doit` has been called, and
/// otherwise the routine will *not* be invoked.
///
- /// This method will block the calling *os thread* if another initialization
+ /// This method will block the calling task if another initialization
/// routine is currently running.
///
/// When this function returns, it is guaranteed that some initialization
fail!("asking for {} which we don't know about", filename);
}
+ pub fn lookup_byte_offset(&self, bpos: BytePos) -> FileMapAndBytePos {
+ let idx = self.lookup_filemap_idx(bpos);
+ let fm = self.files.borrow().get(idx).clone();
+ let offset = bpos - fm.start_pos;
+ FileMapAndBytePos {fm: fm, pos: offset}
+ }
+
+ // Converts an absolute BytePos to a CharPos relative to the filemap and above.
+ pub fn bytepos_to_file_charpos(&self, bpos: BytePos) -> CharPos {
+ debug!("codemap: converting {:?} to char pos", bpos);
+ let idx = self.lookup_filemap_idx(bpos);
+ let files = self.files.borrow();
+ let map = files.get(idx);
+
+ // The number of extra bytes due to multibyte chars in the FileMap
+ let mut total_extra_bytes = 0;
+
+ for mbc in map.multibyte_chars.borrow().iter() {
+ debug!("codemap: {:?}-byte char at {:?}", mbc.bytes, mbc.pos);
+ if mbc.pos < bpos {
+ // every character is at least one byte, so we only
+ // count the actual extra bytes.
+ total_extra_bytes += mbc.bytes - 1;
+ // We should never see a byte position in the middle of a
+ // character
+ assert!(bpos.to_uint() >= mbc.pos.to_uint() + mbc.bytes);
+ } else {
+ break;
+ }
+ }
+
+ assert!(map.start_pos.to_uint() + total_extra_bytes <= bpos.to_uint());
+ CharPos(bpos.to_uint() - map.start_pos.to_uint() - total_extra_bytes)
+ }
+
fn lookup_filemap_idx(&self, pos: BytePos) -> uint {
let files = self.files.borrow();
let files = files;
col: chpos - linechpos
}
}
-
- fn lookup_byte_offset(&self, bpos: BytePos) -> FileMapAndBytePos {
- let idx = self.lookup_filemap_idx(bpos);
- let fm = self.files.borrow().get(idx).clone();
- let offset = bpos - fm.start_pos;
- FileMapAndBytePos {fm: fm, pos: offset}
- }
-
- // Converts an absolute BytePos to a CharPos relative to the filemap.
- fn bytepos_to_file_charpos(&self, bpos: BytePos) -> CharPos {
- debug!("codemap: converting {:?} to char pos", bpos);
- let idx = self.lookup_filemap_idx(bpos);
- let files = self.files.borrow();
- let map = files.get(idx);
-
- // The number of extra bytes due to multibyte chars in the FileMap
- let mut total_extra_bytes = 0;
-
- for mbc in map.multibyte_chars.borrow().iter() {
- debug!("codemap: {:?}-byte char at {:?}", mbc.bytes, mbc.pos);
- if mbc.pos < bpos {
- // every character is at least one byte, so we only
- // count the actual extra bytes.
- total_extra_bytes += mbc.bytes - 1;
- // We should never see a byte position in the middle of a
- // character
- assert!(bpos.to_uint() >= mbc.pos.to_uint() + mbc.bytes);
- } else {
- break;
- }
- }
-
- assert!(map.start_pos.to_uint() + total_extra_bytes <= bpos.to_uint());
- CharPos(bpos.to_uint() - map.start_pos.to_uint() - total_extra_bytes)
- }
}
#[cfg(test)]
ObsoleteOwnedType,
ObsoleteOwnedExpr,
ObsoleteOwnedPattern,
+ ObsoleteOwnedVector,
}
pub trait ParserObsoleteMethods {
"`~` notation for owned pointer patterns",
"use the `box` operator instead of `~`"
),
+ ObsoleteOwnedVector => (
+ "`~[T]` is no longer a type",
+ "use the `Vec` type instead"
+ ),
};
self.report(sp, kind, kind_str, desc);
// OWNED POINTER
self.bump();
match self.token {
- token::IDENT(ref ident, _)
- if "str" == token::get_ident(*ident).get() => {
- // This is OK (for now).
- }
- token::LBRACKET => {} // Also OK.
+ token::LBRACKET =>
+ self.obsolete(self.last_span, ObsoleteOwnedVector),
_ => self.obsolete(self.last_span, ObsoleteOwnedType),
};
TyUniq(self.parse_ty(false))
hi = e.span.hi;
// HACK: turn ~[...] into a ~-vec
ex = match e.node {
- ExprVec(..) | ExprRepeat(..) => ExprVstore(e, ExprVstoreUniq),
+ ExprVec(..) | ExprRepeat(..) => {
+ self.obsolete(self.last_span, ObsoleteOwnedVector);
+ ExprVstore(e, ExprVstoreUniq)
+ }
ExprLit(lit) if lit_is_str(lit) => {
self.obsolete(self.last_span, ObsoleteOwnedExpr);
ExprVstore(e, ExprVstoreUniq)
// HACK: turn `box [...]` into a boxed-vec
ex = match subexpression.node {
ExprVec(..) | ExprRepeat(..) => {
+ self.obsolete(self.last_span, ObsoleteOwnedVector);
ExprVstore(subexpression, ExprVstoreUniq)
}
ExprLit(lit) if lit_is_str(lit) => {
html_root_url = "http://doc.rust-lang.org/")]
#![feature(asm, macro_rules, phase)]
-#![deny(deprecated_owned_vector)]
extern crate getopts;
extern crate regex;
MetricChange, Improvement, Regression, LikelyNoise,
StaticTestFn, StaticTestName, DynTestName, DynTestFn,
run_test, test_main, test_main_static, filter_tests,
- parse_opts, StaticBenchFn, test_main_static_x};
+ parse_opts, StaticBenchFn};
}
pub mod stats;
test_main(args, owned_tests)
}
-pub fn test_main_static_x(args: &[~str], tests: &[TestDescAndFn]) {
- test_main_static(args.iter()
- .map(|x| x.to_string())
- .collect::<Vec<_>>()
- .as_slice(),
- tests)
-}
-
pub enum ColorConfig {
AutoColor,
AlwaysColor,
impl<'a,T: FloatMath + FromPrimitive> Stats<T> for &'a [T] {
// FIXME #11059 handle NaN, inf and overflow
- #[allow(deprecated_owned_vector)]
fn sum(self) -> T {
let mut partials = vec![];
#[test]
fn test_boxplot_nonpositive() {
- #[allow(deprecated_owned_vector)]
fn t(s: &Summary<f64>, expected: String) {
use std::io::MemWriter;
let mut m = MemWriter::new();
html_root_url = "http://doc.rust-lang.org/",
html_playground_url = "http://play.rust-lang.org/")]
#![feature(phase)]
-#![deny(deprecated_owned_vector)]
#[cfg(test)] extern crate debug;
unwrapDI<DIArray>(Elements),
RunTimeLang,
unwrapDI<DIType>(VTableHolder)
-#if LLVM_VERSION_MINOR >= 5
+#if LLVM_VERSION_MINOR >= 4
,UniqueId
#endif
));
Flags,
unwrapDI<DIArray>(Elements),
RunTimeLang
-#if LLVM_VERSION_MINOR >= 5
+#if LLVM_VERSION_MINOR >= 4
,UniqueId
#endif
));
return LLVM_VERSION_MINOR;
}
+extern "C" int
+LLVMVersionMajor() {
+ return LLVM_VERSION_MAJOR;
+}
+
// Note that the two following functions look quite similar to the
// LLVMGetSectionName function. Sadly, it appears that this function only
// returns a char* pointer, which isn't guaranteed to be null-terminated. The
--- /dev/null
+// Copyright 2013-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.
+
+// no-prefer-dynamic
+#![crate_type = "rlib"]
+// compile-flags:-g
+
+struct S1;
+
+impl S1 {
+ fn f(&mut self) { }
+}
+
+
+struct S2;
+
+impl S2 {
+ fn f(&mut self) { }
+}
let clen = seq.len();
let mut seqlen = Future::spawn(proc() {
- let substs = ~[
+ let substs = vec![
(regex!("B"), "(c|g|t)"),
(regex!("D"), "(a|g|t)"),
(regex!("H"), "(a|c|t)"),
seq.len()
});
- let variants = ~[
+ let variants = vec![
regex!("agggtaaa|tttaccct"),
regex!("[cgt]gggtaaa|tttaccc[acg]"),
regex!("a[act]ggtaaa|tttacc[agt]t"),
// except according to those terms.
fn test() {
- let w: ~[int];
+ let w: &mut [int];
w[5] = 0; //~ ERROR use of possibly uninitialized variable: `w`
- //~^ ERROR cannot assign to immutable vec content `w[..]`
- let mut w: ~[int];
+ let mut w: &mut [int];
w[5] = 0; //~ ERROR use of possibly uninitialized variable: `w`
}
#![deny(unreachable_code)]
#![allow(unused_variable)]
#![allow(dead_code)]
-#![allow(deprecated_owned_vector)]
-
fn fail_len(v: Vec<int> ) -> uint {
let mut i = 3;
+++ /dev/null
-// Copyright 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.
-
-#![deny(deprecated_owned_vector)]
-
-fn main() {
- ~[1]; //~ ERROR use of deprecated `~[]`
- //~^ ERROR use of deprecated `~[]`
-}
#![feature(managed_boxes)]
#![forbid(heap_memory)]
#![allow(dead_code)]
-#![allow(deprecated_owned_vector)]
struct Foo {
#![feature(globs)]
#![deny(unused_imports)]
#![allow(dead_code)]
-#![allow(deprecated_owned_vector)]
use cal = bar::c::cc;
#![allow(dead_assignment)]
#![allow(unused_variable)]
#![allow(dead_code)]
-#![allow(deprecated_owned_vector)]
#![deny(unused_mut)]
#![allow(dead_code)]
#![deny(unused_unsafe)]
-#![allow(deprecated_owned_vector)]
mod foo {
--- /dev/null
+// Copyright 2013 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.
+
+// Test for issue #14581.
+
+fn f((a, a): (int, int)) {} //~ ERROR identifier `a` is bound more than once
+
+fn main() {
+ let (a, a) = (1, 1); //~ ERROR identifier `a` is bound more than once
+}
+
--- /dev/null
+// Copyright 2013-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.
+
+// ignore-android: FIXME(#10381)
+
+// aux-build:cross_crate_debuginfo_type_uniquing.rs
+extern crate cross_crate_debuginfo_type_uniquing;
+
+// no-prefer-dynamic
+// compile-flags:-g -Zlto
+
+pub struct C;
+pub fn p() -> C {
+ C
+}
+
+fn main() { }
\ No newline at end of file
--- /dev/null
+-include ../tools.mk
+all:
+ $(RUSTC) foo.rs -Zsave-analysis
--- /dev/null
+// Copyright 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.
+
+struct Foo {
+ f: int
+}
+
+impl Foo {
+ fn bar(&self) -> int {
+ println!("f is {}", self.f);
+ self.f
+ }
+}
+
+trait Tr {
+ fn tar(&self, x: Box<Foo>) -> Foo;
+}
+
+impl Tr for Foo {
+ fn tar(&self, x: Box<Foo>) -> Foo {
+ Foo{ f: self.f + x.f }
+ }
+}
+
+trait Tr2<X, Y: Tr> {
+ fn squid(&self, y: &Y, z: Self) -> Box<X>;
+}
+
+impl Tr2<Foo, Foo> for Foo {
+ fn squid(&self, y: &Foo, z: Foo) -> Box<Foo> {
+ box Foo { f: y.f + z.f + self.f }
+ }
+}
+
+enum En {
+ Var1,
+ Var2,
+ Var3(int, int, Foo)
+}
+
+fn main() {
+ let x = Foo { f: 237 };
+ let _f = x.bar();
+ let en = Var2;
+
+ let _ = match en {
+ Var1 => x.bar(),
+ Var2 => 34,
+ Var3(x, y, f) => f.bar()
+ };
+}
struct Foo;
assert!(Some(box Foo).is_some());
-
- let xs: ~[()] = ~[];
- assert!(Some(xs).is_some());
}
#![feature(macro_rules, managed_boxes)]
#![deny(warnings)]
#![allow(unused_must_use)]
-#![allow(deprecated_owned_vector)]
extern crate debug;
p.borrow_mut().y += 3;
assert_eq!(*p.borrow(), Point {x: 3, y: 5});
- let v = Rc::new(RefCell::new(~[1, 2, 3]));
+ let v = Rc::new(RefCell::new([1, 2, 3]));
v.borrow_mut()[0] = 3;
v.borrow_mut()[1] += 3;
assert_eq!((v.borrow()[0], v.borrow()[1], v.borrow()[2]), (3, 5, 3));
fn visit_char(&mut self) -> bool { true }
- fn visit_estr_box(&mut self) -> bool { true }
- fn visit_estr_uniq(&mut self) -> bool { true }
fn visit_estr_slice(&mut self) -> bool { true }
fn visit_estr_fixed(&mut self,
_sz: uint, _sz2: uint,
fn visit_ptr(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
fn visit_rptr(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
- fn visit_evec_box(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
- fn visit_evec_uniq(&mut self, _mtbl: uint, inner: *TyDesc) -> bool {
- self.types.push("[".to_string());
- unsafe { visit_tydesc(inner, &mut *self as &mut TyVisitor); }
- self.types.push("]".to_string());
- true
- }
fn visit_evec_slice(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
fn visit_evec_fixed(&mut self, _n: uint, _sz: uint, _align: uint,
_mtbl: uint, _inner: *TyDesc) -> bool { true }