<commit_before>mod crosspointer_transmute;
mod transmute_float_to_int;
mod transmute_int_to_bool;
mod transmute_int_to_char;
mod transmute_int_to_float;
mod transmute_num_to_bytes;
mod transmute_ptr_to_ptr;
mod transmute_ptr_to_ref;
mod transmute_ref_to_ref;
mod transmutes_expressible_as_ptr_casts;
mod unsound_collection_transmute;
mod useless_transmute;
mod utils;
mod wrong_transmute;

use clippy_utils::in_constant;
use if_chain::if_chain;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::symbol::sym;

declare_clippy_lint! {
    /// ### What it does
    /// Checks for transmutes that can't ever be correct on any
    /// architecture.
    ///
    /// ### Why is this bad?
    /// It's basically guaranteed to be undefined behaviour.
    ///
    /// ### Known problems
    /// When accessing C, users might want to store pointer
    /// sized objects in `extradata` arguments to save an allocation.
    ///
    /// ### Example
    /// ```ignore
    /// let ptr: *const T = core::intrinsics::transmute('x')
    /// ```
    pub WRONG_TRANSMUTE,
    correctness,
    "transmutes that are confusing at best, undefined behaviour at worst and always useless"
}

// FIXME: Move this to `complexity` again, after #5343 is fixed
declare_clippy_lint! {
    /// ### What it does
    /// Checks for transmutes to the original type of the object
    /// and transmutes that could be a cast.
    ///
    /// ### Why is this bad?
    /// Readability. The code tricks people into thinking that
    /// something complex is going on.
    ///
    /// ### Example
    /// ```rust,ignore
    /// core::intrinsics::transmute(t); // where the result type is the same as `t`'s
    /// ```
    pub USELESS_TRANSMUTE,
    nursery,
    "transmutes that have the same to and from types or could be a cast/coercion"
}

// FIXME: Merge this lint with USELESS_TRANSMUTE once that is out of the nursery.
declare_clippy_lint! {
    /// ### What it does
    ///Checks for transmutes that could be a pointer cast.
    ///
    /// ### Why is this bad?
    /// Readability. The code tricks people into thinking that
    /// something complex is going on.
    ///
    /// ### Example
    ///
    /// ```rust
    /// # let p: *const [i32] = &[];
    /// unsafe { std::mem::transmute::<*const [i32], *const [u16]>(p) };
    /// ```
    /// Use instead:
    /// ```rust
    /// # let p: *const [i32] = &[];
    /// p as *const [u16];
    /// ```
    pub TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
    complexity,
    "transmutes that could be a pointer cast"
}

declare_clippy_lint! {
    /// ### What it does
    /// Checks for transmutes between a type `T` and `*T`.
    ///
    /// ### Why is this bad?
    /// It's easy to mistakenly transmute between a type and a
    /// pointer to that type.
    ///
    /// ### Example
    /// ```rust,ignore
    /// core::intrinsics::transmute(t) // where the result type is the same as
    ///                                // `*t` or `&t`'s
    /// ```
    pub CROSSPOINTER_TRANSMUTE,
    complexity,
    "transmutes that have to or from types that are a pointer to the other"
}

declare_clippy_lint! {
    /// ### What it does
    /// Checks for transmutes from a pointer to a reference.
    ///
    /// ### Why is this bad?
    /// This can always be rewritten with `&` and `*`.
    ///
    /// ### Known problems
    /// - `mem::transmute` in statics and constants is stable from Rust 1.46.0,
    /// while dereferencing raw pointer is not stable yet.
    /// If you need to do this in those places,
    /// you would have to use `transmute` instead.
    ///
    /// ### Example
    /// ```rust,ignore
    /// unsafe {
    ///     let _: &T = std::mem::transmute(p); // where p: *const T
    /// }
    ///
    /// // can be written:
    /// let _: &T = &*p;
    /// ```
    pub TRANSMUTE_PTR_TO_REF,
    complexity,
    "transmutes from a pointer to a reference type"
}

declare_clippy_lint! {
    /// ### What it does
    /// Checks for transmutes from an integer to a `char`.
    ///
    /// ### Why is this bad?
    /// Not every integer is a Unicode scalar value.
    ///
    /// ### Known problems
    /// - [`from_u32`] which this lint suggests using is slower than `transmute`
    /// as it needs to validate the input.
    /// If you are certain that the input is always a valid Unicode scalar value,
    /// use [`from_u32_unchecked`] which is as fast as `transmute`
    /// but has a semantically meaningful name.
    /// - You might want to handle `None` returned from [`from_u32`] instead of calling `unwrap`.
    ///
    /// [`from_u32`]: https://doc.rust-lang.org/std/char/fn.from_u32.html
    /// [`from_u32_unchecked`]: https://doc.rust-lang.org/std/char/fn.from_u32_unchecked.html
    ///
    /// ### Example
    /// ```rust
    /// let x = 1_u32;
    /// unsafe {
    ///     let _: char = std::mem::transmute(x); // where x: u32
    /// }
    ///
    /// // should be:
    /// let _ = std::char::from_u32(x).unwrap();
    /// ```
    pub TRANSMUTE_INT_TO_CHAR,
    complexity,
    "transmutes from an integer to a `char`"
}

declare_clippy_lint! {
    /// ### What it does
    /// Checks for transmutes from a `&[u8]` to a `&str`.
    ///
    /// ### Why is this bad?
    /// Not every byte slice is a valid UTF-8 string.
    ///
    /// ### Known problems
    /// - [`from_utf8`] which this lint suggests using is slower than `transmute`
    /// as it needs to validate the input.
    /// If you are certain that the input is always a valid UTF-8,
    /// use [`from_utf8_unchecked`] which is as fast as `transmute`
    /// but has a semantically meaningful name.
    /// - You might want to handle errors returned from [`from_utf8`] instead of calling `unwrap`.
    ///
    /// [`from_utf8`]: https://doc.rust-lang.org/std/str/fn.from_utf8.html
    /// [`from_utf8_unchecked`]: https://doc.rust-lang.org/std/str/fn.from_utf8_unchecked.html
    ///
    /// ### Example
    /// ```rust
    /// let b: &[u8] = &[1_u8, 2_u8];
    /// unsafe {
    ///     let _: &str = std::mem::transmute(b); // where b: &[u8]
    /// }
    ///
    /// // should be:
    /// let _ = std::str::from_utf8(b).unwrap();
    /// ```
    pub TRANSMUTE_BYTES_TO_STR,
    complexity,
    "transmutes from a `&[u8]` to a `&str`"
}

declare_clippy_lint! {
    /// ### What it does
    /// Checks for transmutes from an integer to a `bool`.
    ///
    /// ### Why is this bad?
    /// This might result in an invalid in-memory representation of a `bool`.
    ///
    /// ### Example
    /// ```rust
    /// let x = 1_u8;
    /// unsafe {
    ///     let _: bool = std::mem::transmute(x); // where x: u8
    /// }
    ///
    /// // should be:
    /// let _: bool = x != 0;
    /// ```
    pub TRANSMUTE_INT_TO_BOOL,
    complexity,
    "transmutes from an integer to a `bool`"
}

declare_clippy_lint! {
    /// ### What it does
    /// Checks for transmutes from an integer to a float.
    ///
    /// ### Why is this bad?
    /// Transmutes are dangerous and error-prone, whereas `from_bits` is intuitive
    /// and safe.
    ///
    /// ### Example
    /// ```rust
    /// unsafe {
    ///     let _: f32 = std::mem::transmute(1_u32); // where x: u32
    /// }
    ///
    /// // should be:
    /// let _: f32 = f32::from_bits(1_u32);
    /// ```
    pub TRANSMUTE_INT_TO_FLOAT,
    complexity,
    "transmutes from an integer to a float"
}

declare_clippy_lint! {
    /// ### What it does
    /// Checks for transmutes from a float to an integer.
    ///
    /// ### Why is this bad?
    /// Transmutes are dangerous and error-prone, whereas `to_bits` is intuitive
    /// and safe.
    ///
    /// ### Example
    /// ```rust
    /// unsafe {
    ///     let _: u32 = std::mem::transmute(1f32);
    /// }
    ///
    /// // should be:
    /// let _: u32 = 1f32.to_bits();
    /// ```
    pub TRANSMUTE_FLOAT_TO_INT,
    complexity,
    "transmutes from a float to an integer"
}

declare_clippy_lint! {
    /// # What it does
    /// Checks for transmutes from a number to an array of `u8`
    ///
    /// ### Why this is bad?
    /// Transmutes are dangerous and error-prone, whereas `to_ne_bytes`
    /// is intuitive and safe.
    ///
    /// ### Example
    /// ```rust
    /// unsafe {
    ///     let x: [u8; 8] = std::mem::transmute(1i64);
    /// }
    ///
    /// // should be
    /// let x: [u8; 8] = 0i64.to_ne_bytes();
    /// ```
    pub TRANSMUTE_NUM_TO_BYTES,
    complexity,
    "transmutes from a number to an array of `u8`"
}

declare_clippy_lint! {
    /// ### What it does
    /// Checks for transmutes from a pointer to a pointer, or
    /// from a reference to a reference.
    ///
    /// ### Why is this bad?
    /// Transmutes are dangerous, and these can instead be
    /// written as casts.
    ///
    /// ### Example
    /// ```rust
    /// let ptr = &1u32 as *const u32;
    /// unsafe {
    ///     // pointer-to-pointer transmute
    ///     let _: *const f32 = std::mem::transmute(ptr);
    ///     // ref-ref transmute
    ///     let _: &f32 = std::mem::transmute(&1u32);
    /// }
    /// // These can be respectively written:
    /// let _ = ptr as *const f32;
    /// let _ = unsafe{ &*(&1u32 as *const u32 as *const f32) };
    /// ```
    pub TRANSMUTE_PTR_TO_PTR,
    pedantic,
    "transmutes from a pointer to a pointer / a reference to a reference"
}

declare_clippy_lint! {
    /// ### What it does
    /// Checks for transmutes between collections whose
    /// types have different ABI, size or alignment.
    ///
    /// ### Why is this bad?
    /// This is undefined behavior.
    ///
    /// ### Known problems
    /// Currently, we cannot know whether a type is a
    /// collection, so we just lint the ones that come with `std`.
    ///
    /// ### Example
    /// ```rust
    /// // different size, therefore likely out-of-bounds memory access
    /// // You absolutely do not want this in your code!
    /// unsafe {
    ///     std::mem::transmute::<_, Vec<u32>>(vec![2_u16])
    /// };
    /// ```
    ///
    /// You must always iterate, map and collect the values:
    ///
    /// ```rust
    /// vec![2_u16].into_iter().map(u32::from).collect::<Vec<_>>();
    /// ```
    pub UNSOUND_COLLECTION_TRANSMUTE,
    correctness,
    "transmute between collections of layout-incompatible types"
}

declare_lint_pass!(Transmute => [
    CROSSPOINTER_TRANSMUTE,
    TRANSMUTE_PTR_TO_REF,
    TRANSMUTE_PTR_TO_PTR,
    USELESS_TRANSMUTE,
    WRONG_TRANSMUTE,
    TRANSMUTE_INT_TO_CHAR,
    TRANSMUTE_BYTES_TO_STR,
    TRANSMUTE_INT_TO_BOOL,
    TRANSMUTE_INT_TO_FLOAT,
    TRANSMUTE_FLOAT_TO_INT,
    TRANSMUTE_NUM_TO_BYTES,
    UNSOUND_COLLECTION_TRANSMUTE,
    TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
]);

impl<'tcx> LateLintPass<'tcx> for Transmute {
    #[allow(clippy::similar_names, clippy::too_many_lines)]
    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
        if_chain! {
            if let ExprKind::Call(path_expr, args) = e.kind;
            if let ExprKind::Path(ref qpath) = path_expr.kind;
            if let Some(def_id) = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id();
            if cx.tcx.is_diagnostic_item(sym::transmute, def_id);
            then {
                // Avoid suggesting from/to bits and dereferencing raw pointers in const contexts.
                // See https://github.com/rust-lang/rust/issues/73736 for progress on making them `const fn`.
                // And see https://github.com/rust-lang/rust/issues/51911 for dereferencing raw pointers.
                let const_context = in_constant(cx, e.hir_id);

                let from_ty = cx.typeck_results().expr_ty(&args[0]);
                let to_ty = cx.typeck_results().expr_ty(e);

                // If useless_transmute is triggered, the other lints can be skipped.
                if useless_transmute::check(cx, e, from_ty, to_ty, args) {
                    return;
                }

                let mut linted = wrong_transmute::check(cx, e, from_ty, to_ty);
                linted |= crosspointer_transmute::check(cx, e, from_ty, to_ty);
                linted |= transmute_ptr_to_ref::check(cx, e, from_ty, to_ty, args, qpath);
                linted |= transmute_int_to_char::check(cx, e, from_ty, to_ty, args);
                linted |= transmute_ref_to_ref::check(cx, e, from_ty, to_ty, args, const_context);
                linted |= transmute_ptr_to_ptr::check(cx, e, from_ty, to_ty, args);
                linted |= transmute_int_to_bool::check(cx, e, from_ty, to_ty, args);
                linted |= transmute_int_to_float::check(cx, e, from_ty, to_ty, args, const_context);
                linted |= transmute_float_to_int::check(cx, e, from_ty, to_ty, args, const_context);
                linted |= transmute_num_to_bytes::check(cx, e, from_ty, to_ty, args, const_context);
                linted |= unsound_collection_transmute::check(cx, e, from_ty, to_ty);

                if !linted {
                    transmutes_expressible_as_ptr_casts::check(cx, e, from_ty, to_ty, args);
                }
            }
        }
    }
}
<commit_msg>Fix doc heading of TRANSMUTE_NUM_TO_BYTES<commit_after>mod crosspointer_transmute;
mod transmute_float_to_int;
mod transmute_int_to_bool;
mod transmute_int_to_char;
mod transmute_int_to_float;
mod transmute_num_to_bytes;
mod transmute_ptr_to_ptr;
mod transmute_ptr_to_ref;
mod transmute_ref_to_ref;
mod transmutes_expressible_as_ptr_casts;
mod unsound_collection_transmute;
mod useless_transmute;
mod utils;
mod wrong_transmute;

use clippy_utils::in_constant;
use if_chain::if_chain;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::symbol::sym;

declare_clippy_lint! {
    /// ### What it does
    /// Checks for transmutes that can't ever be correct on any
    /// architecture.
    ///
    /// ### Why is this bad?
    /// It's basically guaranteed to be undefined behaviour.
    ///
    /// ### Known problems
    /// When accessing C, users might want to store pointer
    /// sized objects in `extradata` arguments to save an allocation.
    ///
    /// ### Example
    /// ```ignore
    /// let ptr: *const T = core::intrinsics::transmute('x')
    /// ```
    pub WRONG_TRANSMUTE,
    correctness,
    "transmutes that are confusing at best, undefined behaviour at worst and always useless"
}

// FIXME: Move this to `complexity` again, after #5343 is fixed
declare_clippy_lint! {
    /// ### What it does
    /// Checks for transmutes to the original type of the object
    /// and transmutes that could be a cast.
    ///
    /// ### Why is this bad?
    /// Readability. The code tricks people into thinking that
    /// something complex is going on.
    ///
    /// ### Example
    /// ```rust,ignore
    /// core::intrinsics::transmute(t); // where the result type is the same as `t`'s
    /// ```
    pub USELESS_TRANSMUTE,
    nursery,
    "transmutes that have the same to and from types or could be a cast/coercion"
}

// FIXME: Merge this lint with USELESS_TRANSMUTE once that is out of the nursery.
declare_clippy_lint! {
    /// ### What it does
    ///Checks for transmutes that could be a pointer cast.
    ///
    /// ### Why is this bad?
    /// Readability. The code tricks people into thinking that
    /// something complex is going on.
    ///
    /// ### Example
    ///
    /// ```rust
    /// # let p: *const [i32] = &[];
    /// unsafe { std::mem::transmute::<*const [i32], *const [u16]>(p) };
    /// ```
    /// Use instead:
    /// ```rust
    /// # let p: *const [i32] = &[];
    /// p as *const [u16];
    /// ```
    pub TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
    complexity,
    "transmutes that could be a pointer cast"
}

declare_clippy_lint! {
    /// ### What it does
    /// Checks for transmutes between a type `T` and `*T`.
    ///
    /// ### Why is this bad?
    /// It's easy to mistakenly transmute between a type and a
    /// pointer to that type.
    ///
    /// ### Example
    /// ```rust,ignore
    /// core::intrinsics::transmute(t) // where the result type is the same as
    ///                                // `*t` or `&t`'s
    /// ```
    pub CROSSPOINTER_TRANSMUTE,
    complexity,
    "transmutes that have to or from types that are a pointer to the other"
}

declare_clippy_lint! {
    /// ### What it does
    /// Checks for transmutes from a pointer to a reference.
    ///
    /// ### Why is this bad?
    /// This can always be rewritten with `&` and `*`.
    ///
    /// ### Known problems
    /// - `mem::transmute` in statics and constants is stable from Rust 1.46.0,
    /// while dereferencing raw pointer is not stable yet.
    /// If you need to do this in those places,
    /// you would have to use `transmute` instead.
    ///
    /// ### Example
    /// ```rust,ignore
    /// unsafe {
    ///     let _: &T = std::mem::transmute(p); // where p: *const T
    /// }
    ///
    /// // can be written:
    /// let _: &T = &*p;
    /// ```
    pub TRANSMUTE_PTR_TO_REF,
    complexity,
    "transmutes from a pointer to a reference type"
}

declare_clippy_lint! {
    /// ### What it does
    /// Checks for transmutes from an integer to a `char`.
    ///
    /// ### Why is this bad?
    /// Not every integer is a Unicode scalar value.
    ///
    /// ### Known problems
    /// - [`from_u32`] which this lint suggests using is slower than `transmute`
    /// as it needs to validate the input.
    /// If you are certain that the input is always a valid Unicode scalar value,
    /// use [`from_u32_unchecked`] which is as fast as `transmute`
    /// but has a semantically meaningful name.
    /// - You might want to handle `None` returned from [`from_u32`] instead of calling `unwrap`.
    ///
    /// [`from_u32`]: https://doc.rust-lang.org/std/char/fn.from_u32.html
    /// [`from_u32_unchecked`]: https://doc.rust-lang.org/std/char/fn.from_u32_unchecked.html
    ///
    /// ### Example
    /// ```rust
    /// let x = 1_u32;
    /// unsafe {
    ///     let _: char = std::mem::transmute(x); // where x: u32
    /// }
    ///
    /// // should be:
    /// let _ = std::char::from_u32(x).unwrap();
    /// ```
    pub TRANSMUTE_INT_TO_CHAR,
    complexity,
    "transmutes from an integer to a `char`"
}

declare_clippy_lint! {
    /// ### What it does
    /// Checks for transmutes from a `&[u8]` to a `&str`.
    ///
    /// ### Why is this bad?
    /// Not every byte slice is a valid UTF-8 string.
    ///
    /// ### Known problems
    /// - [`from_utf8`] which this lint suggests using is slower than `transmute`
    /// as it needs to validate the input.
    /// If you are certain that the input is always a valid UTF-8,
    /// use [`from_utf8_unchecked`] which is as fast as `transmute`
    /// but has a semantically meaningful name.
    /// - You might want to handle errors returned from [`from_utf8`] instead of calling `unwrap`.
    ///
    /// [`from_utf8`]: https://doc.rust-lang.org/std/str/fn.from_utf8.html
    /// [`from_utf8_unchecked`]: https://doc.rust-lang.org/std/str/fn.from_utf8_unchecked.html
    ///
    /// ### Example
    /// ```rust
    /// let b: &[u8] = &[1_u8, 2_u8];
    /// unsafe {
    ///     let _: &str = std::mem::transmute(b); // where b: &[u8]
    /// }
    ///
    /// // should be:
    /// let _ = std::str::from_utf8(b).unwrap();
    /// ```
    pub TRANSMUTE_BYTES_TO_STR,
    complexity,
    "transmutes from a `&[u8]` to a `&str`"
}

declare_clippy_lint! {
    /// ### What it does
    /// Checks for transmutes from an integer to a `bool`.
    ///
    /// ### Why is this bad?
    /// This might result in an invalid in-memory representation of a `bool`.
    ///
    /// ### Example
    /// ```rust
    /// let x = 1_u8;
    /// unsafe {
    ///     let _: bool = std::mem::transmute(x); // where x: u8
    /// }
    ///
    /// // should be:
    /// let _: bool = x != 0;
    /// ```
    pub TRANSMUTE_INT_TO_BOOL,
    complexity,
    "transmutes from an integer to a `bool`"
}

declare_clippy_lint! {
    /// ### What it does
    /// Checks for transmutes from an integer to a float.
    ///
    /// ### Why is this bad?
    /// Transmutes are dangerous and error-prone, whereas `from_bits` is intuitive
    /// and safe.
    ///
    /// ### Example
    /// ```rust
    /// unsafe {
    ///     let _: f32 = std::mem::transmute(1_u32); // where x: u32
    /// }
    ///
    /// // should be:
    /// let _: f32 = f32::from_bits(1_u32);
    /// ```
    pub TRANSMUTE_INT_TO_FLOAT,
    complexity,
    "transmutes from an integer to a float"
}

declare_clippy_lint! {
    /// ### What it does
    /// Checks for transmutes from a float to an integer.
    ///
    /// ### Why is this bad?
    /// Transmutes are dangerous and error-prone, whereas `to_bits` is intuitive
    /// and safe.
    ///
    /// ### Example
    /// ```rust
    /// unsafe {
    ///     let _: u32 = std::mem::transmute(1f32);
    /// }
    ///
    /// // should be:
    /// let _: u32 = 1f32.to_bits();
    /// ```
    pub TRANSMUTE_FLOAT_TO_INT,
    complexity,
    "transmutes from a float to an integer"
}

declare_clippy_lint! {
    /// ### What it does
    /// Checks for transmutes from a number to an array of `u8`
    ///
    /// ### Why this is bad?
    /// Transmutes are dangerous and error-prone, whereas `to_ne_bytes`
    /// is intuitive and safe.
    ///
    /// ### Example
    /// ```rust
    /// unsafe {
    ///     let x: [u8; 8] = std::mem::transmute(1i64);
    /// }
    ///
    /// // should be
    /// let x: [u8; 8] = 0i64.to_ne_bytes();
    /// ```
    pub TRANSMUTE_NUM_TO_BYTES,
    complexity,
    "transmutes from a number to an array of `u8`"
}

declare_clippy_lint! {
    /// ### What it does
    /// Checks for transmutes from a pointer to a pointer, or
    /// from a reference to a reference.
    ///
    /// ### Why is this bad?
    /// Transmutes are dangerous, and these can instead be
    /// written as casts.
    ///
    /// ### Example
    /// ```rust
    /// let ptr = &1u32 as *const u32;
    /// unsafe {
    ///     // pointer-to-pointer transmute
    ///     let _: *const f32 = std::mem::transmute(ptr);
    ///     // ref-ref transmute
    ///     let _: &f32 = std::mem::transmute(&1u32);
    /// }
    /// // These can be respectively written:
    /// let _ = ptr as *const f32;
    /// let _ = unsafe{ &*(&1u32 as *const u32 as *const f32) };
    /// ```
    pub TRANSMUTE_PTR_TO_PTR,
    pedantic,
    "transmutes from a pointer to a pointer / a reference to a reference"
}

declare_clippy_lint! {
    /// ### What it does
    /// Checks for transmutes between collections whose
    /// types have different ABI, size or alignment.
    ///
    /// ### Why is this bad?
    /// This is undefined behavior.
    ///
    /// ### Known problems
    /// Currently, we cannot know whether a type is a
    /// collection, so we just lint the ones that come with `std`.
    ///
    /// ### Example
    /// ```rust
    /// // different size, therefore likely out-of-bounds memory access
    /// // You absolutely do not want this in your code!
    /// unsafe {
    ///     std::mem::transmute::<_, Vec<u32>>(vec![2_u16])
    /// };
    /// ```
    ///
    /// You must always iterate, map and collect the values:
    ///
    /// ```rust
    /// vec![2_u16].into_iter().map(u32::from).collect::<Vec<_>>();
    /// ```
    pub UNSOUND_COLLECTION_TRANSMUTE,
    correctness,
    "transmute between collections of layout-incompatible types"
}

declare_lint_pass!(Transmute => [
    CROSSPOINTER_TRANSMUTE,
    TRANSMUTE_PTR_TO_REF,
    TRANSMUTE_PTR_TO_PTR,
    USELESS_TRANSMUTE,
    WRONG_TRANSMUTE,
    TRANSMUTE_INT_TO_CHAR,
    TRANSMUTE_BYTES_TO_STR,
    TRANSMUTE_INT_TO_BOOL,
    TRANSMUTE_INT_TO_FLOAT,
    TRANSMUTE_FLOAT_TO_INT,
    TRANSMUTE_NUM_TO_BYTES,
    UNSOUND_COLLECTION_TRANSMUTE,
    TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
]);

impl<'tcx> LateLintPass<'tcx> for Transmute {
    #[allow(clippy::similar_names, clippy::too_many_lines)]
    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
        if_chain! {
            if let ExprKind::Call(path_expr, args) = e.kind;
            if let ExprKind::Path(ref qpath) = path_expr.kind;
            if let Some(def_id) = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id();
            if cx.tcx.is_diagnostic_item(sym::transmute, def_id);
            then {
                // Avoid suggesting from/to bits and dereferencing raw pointers in const contexts.
                // See https://github.com/rust-lang/rust/issues/73736 for progress on making them `const fn`.
                // And see https://github.com/rust-lang/rust/issues/51911 for dereferencing raw pointers.
                let const_context = in_constant(cx, e.hir_id);

                let from_ty = cx.typeck_results().expr_ty(&args[0]);
                let to_ty = cx.typeck_results().expr_ty(e);

                // If useless_transmute is triggered, the other lints can be skipped.
                if useless_transmute::check(cx, e, from_ty, to_ty, args) {
                    return;
                }

                let mut linted = wrong_transmute::check(cx, e, from_ty, to_ty);
                linted |= crosspointer_transmute::check(cx, e, from_ty, to_ty);
                linted |= transmute_ptr_to_ref::check(cx, e, from_ty, to_ty, args, qpath);
                linted |= transmute_int_to_char::check(cx, e, from_ty, to_ty, args);
                linted |= transmute_ref_to_ref::check(cx, e, from_ty, to_ty, args, const_context);
                linted |= transmute_ptr_to_ptr::check(cx, e, from_ty, to_ty, args);
                linted |= transmute_int_to_bool::check(cx, e, from_ty, to_ty, args);
                linted |= transmute_int_to_float::check(cx, e, from_ty, to_ty, args, const_context);
                linted |= transmute_float_to_int::check(cx, e, from_ty, to_ty, args, const_context);
                linted |= transmute_num_to_bytes::check(cx, e, from_ty, to_ty, args, const_context);
                linted |= unsound_collection_transmute::check(cx, e, from_ty, to_ty);

                if !linted {
                    transmutes_expressible_as_ptr_casts::check(cx, e, from_ty, to_ty, args);
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

//!
//! A tree stream is the result of annotating an annotated stream. This forms a tree structure with the original input
//! stream at the leaves.
//!

use super::countable::*;
use super::symbol_reader::*;
use super::annotated_stream::*;

///
/// Represents a stream that has been decomposed into a tree
///
#[derive(Clone)]
pub struct TreeStream<InputSymbol, TokenType> {
    /// How the original input stream maps onto tokens
    tokens: AnnotatedStream<InputSymbol, TokenType>,

    /// The hierarchy of annotations. As a tree, the 'root' is considered to be the last entry in this list (it's built from the bottom up)
    annotations: Vec<AnnotatedStream<TokenType, TokenType>>
}

impl<InputSymbol: Clone+Ord+Countable, TokenType: Clone+Ord+Countable+'static> TreeStream<InputSymbol, TokenType> {
    ///
    /// Creates a new tree stream from a tokenized stream
    ///
    pub fn new_with_tokens(tokens: AnnotatedStream<InputSymbol, TokenType>) -> Self {
        TreeStream { tokens: tokens, annotations: vec![] }
    }

    ///
    /// Reads the input that made up this tree stream
    ///
    pub fn read_input<'a>(&'a self) -> Box<SymbolReader<InputSymbol>+'a> {
        self.tokens.read_input()
    }

    ///
    /// Works out the depth of this tree
    ///
    pub fn depth(&self) -> usize {
        self.annotations.len()+1
    }

    ///
    /// Reads a the tokens on a particular level of the tree as a stream
    ///
    /// `0` is the top-most level of the tree, and `depth()-1` represent the bottom-most level (the level containing the tokens)
    ///
    pub fn read_level_tokens<'a>(&'a self, depth: usize) -> Box<SymbolReader<Token<TokenType>>+'a> {
        if depth == self.annotations.len() {
            // Just the tokens, mapping onto the original input stream
            self.tokens.read_tokens()
        } else {
            // Build up a symbol reader from the output and input of this stream
            let level  = (self.annotations.len()-1) - depth;
            let stream = &self.annotations[level];

            let mut tokens   = vec![];
            let mut last_pos = 0..0;
            let mut reader   = stream.read_tokens();

            loop {
                if let Some(level_token) = reader.next_symbol() {
                    // Append input symbols if there is a gap
                    if last_pos.end != level_token.location.start {
                        let gap_range         = last_pos.end..level_token.location.start;
                        let from_higher_level = stream.input_for_range(gap_range.clone());

                        for pos in gap_range.clone() {
                            tokens.push(Token::new(pos..pos+1, from_higher_level[pos-gap_range.start].clone()));
                        }
                    }

                    // Update the last pos so we can detect gaps after it
                    last_pos = level_token.location.clone();

                    // Add this token
                    tokens.push(level_token);
                } else {
                    // End of stream
                    break;
                }
            }

            // Append input tokens from the end of the stream
            let end_pos  = stream.input_len();
            let end_gap  = last_pos.end..end_pos;
            let from_end = stream.input_for_range(end_gap.clone());

            for pos in end_gap.clone() {
                tokens.push(Token::new(pos..pos+1, from_end[pos-end_gap.start].clone()));
            }

            // Result is a new vector stream
            Box::new(VecReader::from_vec(tokens))
        }
    }

    ///
    /// Reads a particular level of the tree as a stream
    ///
    /// `0` is the top-most level of the tree, and `depth()-1` represent the bottom-most level (the level containing the tokens)
    ///
    pub fn read_level<'a>(&'a self, depth: usize) -> Box<SymbolReader<TokenType>+'a> {
        if depth == self.annotations.len() {
            // Just the tokens; this level is flat
            self.tokens.read_output()
        } else {
            // Need to read 'through' the tree to deal with gaps to create the whole stream at this level
            unimplemented!()
        }
    }
}

///
/// Symbol reader that reads a 'level' of a tree
///
/// If the level has gaps in it, then those are filled in using the tokens from the level above
///
struct LevelReader<'a, InputSymbol: 'a, TokenType: 'static> {
    // The source treestream that is being read
    source: &'a TreeStream<InputSymbol, TokenType>,

    // The stack of levels being processed: the readers and the last token seen from them
    stack: Vec<(Box<SymbolReader<Token<TokenType>>+'a>, Option<Token<TokenType>>)>
}

#[cfg(test)]
mod test {
    use super::super::*;

    #[derive(Ord, PartialOrd, Eq, PartialEq, Clone)]
    enum TestToken {
        Digit,
        Identifier,
        Whitespace
    }

    impl Countable for TestToken {
        fn next(&self) -> Self {
            match *self {
                TestToken::Digit        => TestToken::Identifier,
                TestToken::Identifier   => TestToken::Whitespace,
                TestToken::Whitespace   => TestToken::Digit
            }
        }

        fn prev(&self) -> Self {
            match *self {
                TestToken::Digit        => TestToken::Whitespace,
                TestToken::Identifier   => TestToken::Digit,
                TestToken::Whitespace   => TestToken::Identifier
            }
        }
    }

    fn create_simple_tokenizer() -> SymbolRangeDfa<char, TestToken> {
        let mut token_matcher = TokenMatcher::new();

        token_matcher.add_pattern(MatchRange('0', '9').repeat_forever(1), TestToken::Digit);
        token_matcher.add_pattern(MatchRange('a', 'z').repeat_forever(1), TestToken::Identifier);
        token_matcher.add_pattern(" ".repeat_forever(1), TestToken::Whitespace);

        token_matcher.prepare_to_match()
    }

    #[test]
    pub fn can_iterate_over_base_stream() {
        let tokenizer        = create_simple_tokenizer();
        let tokenized_stream = AnnotatedStream::from_tokenizer(&tokenizer, "a+1".read_symbols());
        let tokenized_tree   = TreeStream::new_with_tokens(tokenized_stream);

        assert!(tokenized_tree.depth() == 1);
        assert!(tokenized_tree.read_input().to_vec() == vec!['a', '+', '1']);
    }
}
<commit_msg>Deal with reading a level as a series of tokens just by mapping the other function<commit_after>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

//!
//! A tree stream is the result of annotating an annotated stream. This forms a tree structure with the original input
//! stream at the leaves.
//!

use super::countable::*;
use super::symbol_reader::*;
use super::annotated_stream::*;

///
/// Represents a stream that has been decomposed into a tree
///
#[derive(Clone)]
pub struct TreeStream<InputSymbol, TokenType> {
    /// How the original input stream maps onto tokens
    tokens: AnnotatedStream<InputSymbol, TokenType>,

    /// The hierarchy of annotations. As a tree, the 'root' is considered to be the last entry in this list (it's built from the bottom up)
    annotations: Vec<AnnotatedStream<TokenType, TokenType>>
}

impl<InputSymbol: Clone+Ord+Countable, TokenType: Clone+Ord+Countable+'static> TreeStream<InputSymbol, TokenType> {
    ///
    /// Creates a new tree stream from a tokenized stream
    ///
    pub fn new_with_tokens(tokens: AnnotatedStream<InputSymbol, TokenType>) -> Self {
        TreeStream { tokens: tokens, annotations: vec![] }
    }

    ///
    /// Reads the input that made up this tree stream
    ///
    pub fn read_input<'a>(&'a self) -> Box<SymbolReader<InputSymbol>+'a> {
        self.tokens.read_input()
    }

    ///
    /// Works out the depth of this tree
    ///
    pub fn depth(&self) -> usize {
        self.annotations.len()+1
    }

    ///
    /// Reads a the tokens on a particular level of the tree as a stream
    ///
    /// `0` is the top-most level of the tree, and `depth()-1` represent the bottom-most level (the level containing the tokens)
    ///
    pub fn read_level_tokens<'a>(&'a self, depth: usize) -> Box<SymbolReader<Token<TokenType>>+'a> {
        if depth == self.annotations.len() {
            // Just the tokens, mapping onto the original input stream
            self.tokens.read_tokens()
        } else {
            // Build up a symbol reader from the output and input of this stream
            let level  = (self.annotations.len()-1) - depth;
            let stream = &self.annotations[level];

            let mut tokens   = vec![];
            let mut last_pos = 0..0;
            let mut reader   = stream.read_tokens();

            loop {
                if let Some(level_token) = reader.next_symbol() {
                    // Append input symbols if there is a gap
                    if last_pos.end != level_token.location.start {
                        let gap_range         = last_pos.end..level_token.location.start;
                        let from_higher_level = stream.input_for_range(gap_range.clone());

                        for pos in gap_range.clone() {
                            tokens.push(Token::new(pos..pos+1, from_higher_level[pos-gap_range.start].clone()));
                        }
                    }

                    // Update the last pos so we can detect gaps after it
                    last_pos = level_token.location.clone();

                    // Add this token
                    tokens.push(level_token);
                } else {
                    // End of stream
                    break;
                }
            }

            // Append input tokens from the end of the stream
            let end_pos  = stream.input_len();
            let end_gap  = last_pos.end..end_pos;
            let from_end = stream.input_for_range(end_gap.clone());

            for pos in end_gap.clone() {
                tokens.push(Token::new(pos..pos+1, from_end[pos-end_gap.start].clone()));
            }

            // Result is a new vector stream
            Box::new(VecReader::from_vec(tokens))
        }
    }

    ///
    /// Reads a particular level of the tree as a stream
    ///
    /// `0` is the top-most level of the tree, and `depth()-1` represent the bottom-most level (the level containing the tokens)
    ///
    pub fn read_level<'a>(&'a self, depth: usize) -> Box<SymbolReader<TokenType>+'a> {
        Box::new(self.read_level_tokens(depth).map_symbols(|token| token.output))
    }
}

///
/// Symbol reader that reads a 'level' of a tree
///
/// If the level has gaps in it, then those are filled in using the tokens from the level above
///
struct LevelReader<'a, InputSymbol: 'a, TokenType: 'static> {
    // The source treestream that is being read
    source: &'a TreeStream<InputSymbol, TokenType>,

    // The stack of levels being processed: the readers and the last token seen from them
    stack: Vec<(Box<SymbolReader<Token<TokenType>>+'a>, Option<Token<TokenType>>)>
}

#[cfg(test)]
mod test {
    use super::super::*;

    #[derive(Ord, PartialOrd, Eq, PartialEq, Clone)]
    enum TestToken {
        Digit,
        Identifier,
        Whitespace
    }

    impl Countable for TestToken {
        fn next(&self) -> Self {
            match *self {
                TestToken::Digit        => TestToken::Identifier,
                TestToken::Identifier   => TestToken::Whitespace,
                TestToken::Whitespace   => TestToken::Digit
            }
        }

        fn prev(&self) -> Self {
            match *self {
                TestToken::Digit        => TestToken::Whitespace,
                TestToken::Identifier   => TestToken::Digit,
                TestToken::Whitespace   => TestToken::Identifier
            }
        }
    }

    fn create_simple_tokenizer() -> SymbolRangeDfa<char, TestToken> {
        let mut token_matcher = TokenMatcher::new();

        token_matcher.add_pattern(MatchRange('0', '9').repeat_forever(1), TestToken::Digit);
        token_matcher.add_pattern(MatchRange('a', 'z').repeat_forever(1), TestToken::Identifier);
        token_matcher.add_pattern(" ".repeat_forever(1), TestToken::Whitespace);

        token_matcher.prepare_to_match()
    }

    #[test]
    pub fn can_iterate_over_base_stream() {
        let tokenizer        = create_simple_tokenizer();
        let tokenized_stream = AnnotatedStream::from_tokenizer(&tokenizer, "a+1".read_symbols());
        let tokenized_tree   = TreeStream::new_with_tokens(tokenized_stream);

        assert!(tokenized_tree.depth() == 1);
        assert!(tokenized_tree.read_input().to_vec() == vec!['a', '+', '1']);
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::io::Read;
use std::marker::PhantomData;
use std::mem;
use std::sync::atomic;

use kernel32;
use winapi;

use consts::{self, KeyPress};
use ::error;
use ::Result;
use SIGWINCH;

pub type Handle = winapi::HANDLE;
pub type Mode = winapi::DWORD;
pub const STDIN_FILENO: winapi::DWORD = winapi::STD_INPUT_HANDLE;
pub const STDOUT_FILENO: winapi::DWORD = winapi::STD_OUTPUT_HANDLE;

fn get_std_handle(fd: winapi::DWORD) -> Result<winapi::HANDLE> {
    let handle = unsafe { kernel32::GetStdHandle(fd) };
    if handle == winapi::INVALID_HANDLE_VALUE {
        try!(Err(io::Error::last_os_error()));
    } else if handle.is_null() {
        try!(Err(io::Error::new(io::ErrorKind::Other,
                                "no stdio handle available for this process")));
    }
    Ok(handle)
}

#[macro_export]
macro_rules! check {
    ($funcall:expr) => {
        {
        let rc = unsafe { $funcall };
        if rc == 0 {
            try!(Err(io::Error::last_os_error()));
        }
        rc
        }
    };
}

/// Try to get the number of columns in the current terminal, or assume 80 if it fails.
pub fn get_columns(handle: Handle) -> usize {
    let mut info = unsafe { mem::zeroed() };
    match unsafe { kernel32::GetConsoleScreenBufferInfo(handle, &mut info) } {
        0 => 80,
        _ => info.dwSize.X as usize,
    }
}

/// Checking for an unsupported TERM in windows is a no-op
pub fn is_unsupported_term() -> bool {
    false
}

fn get_console_mode(handle: winapi::HANDLE) -> Result<Mode> {
    let mut original_mode = 0;
    check!(kernel32::GetConsoleMode(handle, &mut original_mode));
    Ok(original_mode)
}

/// Return whether or not STDIN, STDOUT or STDERR is a TTY
pub fn is_a_tty(fd: winapi::DWORD) -> bool {
    let handle = get_std_handle(fd);
    match handle {
        Ok(handle) => {
            // If this function doesn't fail then fd is a TTY
            get_console_mode(handle).is_ok()
        }
        Err(_) => false,
    }
}

/// Enable raw mode for the TERM
pub fn enable_raw_mode() -> Result<Mode> {
    let handle = try!(get_std_handle(STDIN_FILENO));
    let original_mode = try!(get_console_mode(handle));
    let raw = original_mode &
              !(winapi::wincon::ENABLE_LINE_INPUT | winapi::wincon::ENABLE_ECHO_INPUT |
                winapi::wincon::ENABLE_PROCESSED_INPUT);
    check!(kernel32::SetConsoleMode(handle, raw));
    Ok(original_mode)
}

/// Disable Raw mode for the term
pub fn disable_raw_mode(original_mode: Mode) -> Result<()> {
    let handle = try!(get_std_handle(STDIN_FILENO));
    check!(kernel32::SetConsoleMode(handle, original_mode));
    Ok(())
}

pub fn stdout_handle() -> Result<Handle> {
    let handle = try!(get_std_handle(STDOUT_FILENO));
    Ok(handle)
}

/// Console input reader
pub struct RawReader<R> {
    handle: winapi::HANDLE,
    buf: Option<u16>,
    phantom: PhantomData<R>,
}

impl<R: Read> RawReader<R> {
    pub fn new(_: R) -> Result<RawReader<R>> {
        let handle = try!(get_std_handle(STDIN_FILENO));
        Ok(RawReader {
            handle: handle,
            buf: None,
            phantom: PhantomData,
        })
    }

    pub fn next_key(&mut self, _: bool) -> Result<KeyPress> {
        use std::char::decode_utf16;

        let mut rec: winapi::INPUT_RECORD = unsafe { mem::zeroed() };
        let mut count = 0;
        let mut esc_seen = false;
        loop {
            // TODO GetNumberOfConsoleInputEvents
            check!(kernel32::ReadConsoleInputW(self.handle,
                                               &mut rec,
                                               1 as winapi::DWORD,
                                               &mut count));

            // TODO ENABLE_WINDOW_INPUT ???
            if rec.EventType == winapi::WINDOW_BUFFER_SIZE_EVENT {
                SIGWINCH.store(true, atomic::Ordering::SeqCst);
                return Err(error::ReadlineError::WindowResize);
            } else if rec.EventType != winapi::KEY_EVENT {
                continue;
            }
            let key_event = unsafe { rec.KeyEvent() };
            // writeln!(io::stderr(), "key_event: {:?}", key_event).unwrap();
            if key_event.bKeyDown == 0 &&
               key_event.wVirtualKeyCode != winapi::VK_MENU as winapi::WORD {
                continue;
            }

            let ctrl = key_event.dwControlKeyState &
                       (winapi::LEFT_CTRL_PRESSED | winapi::RIGHT_CTRL_PRESSED) !=
                       0;
            let meta = (key_event.dwControlKeyState &
                        (winapi::LEFT_ALT_PRESSED | winapi::RIGHT_ALT_PRESSED) !=
                        0) || esc_seen;

            let utf16 = key_event.UnicodeChar;
            if utf16 == 0 {
                match key_event.wVirtualKeyCode as i32 {
                    winapi::VK_LEFT => return Ok(KeyPress::Left),
                    winapi::VK_RIGHT => return Ok(KeyPress::Right),
                    winapi::VK_UP => return Ok(KeyPress::Up),
                    winapi::VK_DOWN => return Ok(KeyPress::Down),
                    winapi::VK_DELETE => return Ok(KeyPress::Delete),
                    winapi::VK_HOME => return Ok(KeyPress::Home),
                    winapi::VK_END => return Ok(KeyPress::End),
                    _ => continue,
                };
            } else if utf16 == 27 {
                esc_seen = true;
                continue;
            } else {
                // TODO How to support surrogate pair ?
                self.buf = Some(utf16);
                let orc = decode_utf16(self).next();
                if orc.is_none() {
                    return Err(error::ReadlineError::Eof);
                }
                let c = try!(orc.unwrap());
                if meta {
                    match c {
                        'b' | 'B' => return Ok(KeyPress::Meta('B')),
                        'c' | 'C' => return Ok(KeyPress::Meta('C')),
                        'd' | 'D' => return Ok(KeyPress::Meta('D')),
                        'f' | 'F' => return Ok(KeyPress::Meta('F')),
                        'l' | 'L' => return Ok(KeyPress::Meta('L')),
                        't' | 'T' => return Ok(KeyPress::Meta('T')),
                        'u' | 'U' => return Ok(KeyPress::Meta('U')),
                        'y' | 'Y' => return Ok(KeyPress::Meta('Y')),
                        _ => return Ok(KeyPress::UNKNOWN_ESC_SEQ),
                    }
                } else {
                    return Ok(consts::char_to_key_press(c));
                }
            }
        }
    }
}

impl<R: Read> Iterator for RawReader<R> {
    type Item = u16;

    fn next(&mut self) -> Option<u16> {
        let buf = self.buf;
        self.buf = None;
        buf
    }
}
<commit_msg>Fix #55.<commit_after>use std::io;
use std::io::Read;
use std::marker::PhantomData;
use std::mem;
use std::sync::atomic;

use kernel32;
use winapi;

use consts::{self, KeyPress};
use ::error;
use ::Result;
use SIGWINCH;

pub type Handle = winapi::HANDLE;
pub type Mode = winapi::DWORD;
pub const STDIN_FILENO: winapi::DWORD = winapi::STD_INPUT_HANDLE;
pub const STDOUT_FILENO: winapi::DWORD = winapi::STD_OUTPUT_HANDLE;

fn get_std_handle(fd: winapi::DWORD) -> Result<winapi::HANDLE> {
    let handle = unsafe { kernel32::GetStdHandle(fd) };
    if handle == winapi::INVALID_HANDLE_VALUE {
        try!(Err(io::Error::last_os_error()));
    } else if handle.is_null() {
        try!(Err(io::Error::new(io::ErrorKind::Other,
                                "no stdio handle available for this process")));
    }
    Ok(handle)
}

#[macro_export]
macro_rules! check {
    ($funcall:expr) => {
        {
        let rc = unsafe { $funcall };
        if rc == 0 {
            try!(Err(io::Error::last_os_error()));
        }
        rc
        }
    };
}

/// Try to get the number of columns in the current terminal, or assume 80 if it fails.
pub fn get_columns(handle: Handle) -> usize {
    let mut info = unsafe { mem::zeroed() };
    match unsafe { kernel32::GetConsoleScreenBufferInfo(handle, &mut info) } {
        0 => 80,
        _ => info.dwSize.X as usize,
    }
}

/// Checking for an unsupported TERM in windows is a no-op
pub fn is_unsupported_term() -> bool {
    false
}

fn get_console_mode(handle: winapi::HANDLE) -> Result<Mode> {
    let mut original_mode = 0;
    check!(kernel32::GetConsoleMode(handle, &mut original_mode));
    Ok(original_mode)
}

/// Return whether or not STDIN, STDOUT or STDERR is a TTY
pub fn is_a_tty(fd: winapi::DWORD) -> bool {
    let handle = get_std_handle(fd);
    match handle {
        Ok(handle) => {
            // If this function doesn't fail then fd is a TTY
            get_console_mode(handle).is_ok()
        }
        Err(_) => false,
    }
}

/// Enable raw mode for the TERM
pub fn enable_raw_mode() -> Result<Mode> {
    let handle = try!(get_std_handle(STDIN_FILENO));
    let original_mode = try!(get_console_mode(handle));
    // Disable these modes
    let raw = original_mode &
              !(winapi::wincon::ENABLE_LINE_INPUT | winapi::wincon::ENABLE_ECHO_INPUT |
                winapi::wincon::ENABLE_PROCESSED_INPUT);
    // Enable these modes
    let raw = raw | winapi::wincon::ENABLE_EXTENDED_FLAGS;
    let raw = raw | winapi::wincon::ENABLE_INSERT_MODE;
    let raw = raw | winapi::wincon::ENABLE_QUICK_EDIT_MODE;
    let raw = raw | winapi::wincon::ENABLE_WINDOW_INPUT;
    check!(kernel32::SetConsoleMode(handle, raw));
    Ok(original_mode)
}

/// Disable Raw mode for the term
pub fn disable_raw_mode(original_mode: Mode) -> Result<()> {
    let handle = try!(get_std_handle(STDIN_FILENO));
    check!(kernel32::SetConsoleMode(handle, original_mode));
    Ok(())
}

pub fn stdout_handle() -> Result<Handle> {
    let handle = try!(get_std_handle(STDOUT_FILENO));
    Ok(handle)
}

/// Console input reader
pub struct RawReader<R> {
    handle: winapi::HANDLE,
    buf: Option<u16>,
    phantom: PhantomData<R>,
}

impl<R: Read> RawReader<R> {
    pub fn new(_: R) -> Result<RawReader<R>> {
        let handle = try!(get_std_handle(STDIN_FILENO));
        Ok(RawReader {
            handle: handle,
            buf: None,
            phantom: PhantomData,
        })
    }

    pub fn next_key(&mut self, _: bool) -> Result<KeyPress> {
        use std::char::decode_utf16;
        use winapi::{LEFT_ALT_PRESSED, LEFT_CTRL_PRESSED, RIGHT_ALT_PRESSED, RIGHT_CTRL_PRESSED};

        let mut rec: winapi::INPUT_RECORD = unsafe { mem::zeroed() };
        let mut count = 0;
        let mut esc_seen = false;
        loop {
            // TODO GetNumberOfConsoleInputEvents
            check!(kernel32::ReadConsoleInputW(self.handle,
                                               &mut rec,
                                               1 as winapi::DWORD,
                                               &mut count));

            // TODO ENABLE_WINDOW_INPUT ???
            if rec.EventType == winapi::WINDOW_BUFFER_SIZE_EVENT {
                SIGWINCH.store(true, atomic::Ordering::SeqCst);
                return Err(error::ReadlineError::WindowResize);
            } else if rec.EventType != winapi::KEY_EVENT {
                continue;
            }
            let key_event = unsafe { rec.KeyEvent() };
            // writeln!(io::stderr(), "key_event: {:?}", key_event).unwrap();
            if key_event.bKeyDown == 0 &&
               key_event.wVirtualKeyCode != winapi::VK_MENU as winapi::WORD {
                continue;
            }

            // let alt_gr = key_event.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_ALT_PRESSED) ==
            // (LEFT_CTRL_PRESSED | RIGHT_ALT_PRESSED);
            let alt = key_event.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED) ==
                      (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED);
            // let ctrl = key_event.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED) ==
            // (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED);
            let meta = alt || esc_seen;

            let utf16 = key_event.UnicodeChar;
            if utf16 == 0 {
                match key_event.wVirtualKeyCode as i32 {
                    winapi::VK_LEFT => return Ok(KeyPress::Left),
                    winapi::VK_RIGHT => return Ok(KeyPress::Right),
                    winapi::VK_UP => return Ok(KeyPress::Up),
                    winapi::VK_DOWN => return Ok(KeyPress::Down),
                    winapi::VK_DELETE => return Ok(KeyPress::Delete),
                    winapi::VK_HOME => return Ok(KeyPress::Home),
                    winapi::VK_END => return Ok(KeyPress::End),
                    _ => continue,
                };
            } else if utf16 == 27 {
                esc_seen = true;
                continue;
            } else {
                // TODO How to support surrogate pair ?
                self.buf = Some(utf16);
                let orc = decode_utf16(self).next();
                if orc.is_none() {
                    return Err(error::ReadlineError::Eof);
                }
                let c = try!(orc.unwrap());
                if meta {
                    match c {
                        'b' | 'B' => return Ok(KeyPress::Meta('B')),
                        'c' | 'C' => return Ok(KeyPress::Meta('C')),
                        'd' | 'D' => return Ok(KeyPress::Meta('D')),
                        'f' | 'F' => return Ok(KeyPress::Meta('F')),
                        'l' | 'L' => return Ok(KeyPress::Meta('L')),
                        't' | 'T' => return Ok(KeyPress::Meta('T')),
                        'u' | 'U' => return Ok(KeyPress::Meta('U')),
                        'y' | 'Y' => return Ok(KeyPress::Meta('Y')),
                        _ => return Ok(KeyPress::UNKNOWN_ESC_SEQ),
                    }
                } else {
                    return Ok(consts::char_to_key_press(c));
                }
            }
        }
    }
}

impl<R: Read> Iterator for RawReader<R> {
    type Item = u16;

    fn next(&mut self) -> Option<u16> {
        let buf = self.buf;
        self.buf = None;
        buf
    }
}
<|endoftext|>


<commit_before>mod crc;
#[macro_use]
mod macros;

pub use self::crc::{crc8, crc16};

// Convert one to four byte slices into an unsigned 32-bit number.
//
// NOTE: This assumes big-endian since most numbers in the FLAC binary are
// that endianness.
#[inline]
pub fn to_u32(bytes: &[u8]) -> u32 {
  let length = bytes.len();

  debug_assert!(length <= 4);

  (0..length).fold(0, |result, i|
    result + ((bytes[i] as u32) << ((length - 1 - i) * 8))
  )
}

pub fn extend_sign(value: u32, bit_count: usize) -> i32 {
  if bit_count >= 32 || value < (1 << (bit_count - 1)) {
    value as i32
  } else {
    (value as i32).wrapping_sub(1 << bit_count)
  }
}

#[cfg(test)]
mod tests {
  use super::*;

  #[test]
  #[should_panic]
  fn test_panic_to_u32() {
    to_u32(&[0x00, 0x00, 0x00, 0x00, 0x00]);
  }

  #[test]
  fn test_to_u32() {
    let bytes = [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef];

    assert_eq!(to_u32(&bytes[0..1]), 0x00000001);
    assert_eq!(to_u32(&bytes[3..5]), 0x00006789);
    assert_eq!(to_u32(&bytes[1..4]), 0x00234567);
    assert_eq!(to_u32(&bytes[4..]), 0x89abcdef);
  }

  #[test]
  fn test_extend_sign() {
    assert_eq!(extend_sign(32, 6), -32);
    assert_eq!(extend_sign(31, 6), 31);
    assert_eq!(extend_sign(128, 8), -128);
    assert_eq!(extend_sign(127, 8), 127);

    assert_eq!(extend_sign(2048, 12), -2048);
    assert_eq!(extend_sign(2047, 12), 2047);
    assert_eq!(extend_sign(32768, 16), -32768);
    assert_eq!(extend_sign(32767, 16), 32767);

    assert_eq!(extend_sign(8388608, 24), -8388608);
    assert_eq!(extend_sign(8388607, 24), 8388607);
    assert_eq!(extend_sign(2147483648, 32), -2147483648);
    assert_eq!(extend_sign(2147483647, 32), 2147483647);
  }
}
<commit_msg>Add `utility::resize_producer` for convenience<commit_after>mod crc;
#[macro_use]
mod macros;

pub use self::crc::{crc8, crc16};

use nom::{FileProducer, Move, Needed};

// Convert one to four byte slices into an unsigned 32-bit number.
//
// NOTE: This assumes big-endian since most numbers in the FLAC binary are
// that endianness.
#[inline]
pub fn to_u32(bytes: &[u8]) -> u32 {
  let length = bytes.len();

  debug_assert!(length <= 4);

  (0..length).fold(0, |result, i|
    result + ((bytes[i] as u32) << ((length - 1 - i) * 8))
  )
}

pub fn extend_sign(value: u32, bit_count: usize) -> i32 {
  if bit_count >= 32 || value < (1 << (bit_count - 1)) {
    value as i32
  } else {
    (value as i32).wrapping_sub(1 << bit_count)
  }
}

pub fn resize_producer(producer: &mut FileProducer,
                       await: &Move,
                       current_size: usize)
                       -> Option<usize> {
  let mut result = None;

  if let Move::Await(needed) = *await {
    if let Needed::Size(size) = needed {
      if size > current_size {
        producer.resize(size);
        result = Some(size);
      }
    }
  }

  result
}

#[cfg(test)]
mod tests {
  use super::*;

  #[test]
  #[should_panic]
  fn test_panic_to_u32() {
    to_u32(&[0x00, 0x00, 0x00, 0x00, 0x00]);
  }

  #[test]
  fn test_to_u32() {
    let bytes = [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef];

    assert_eq!(to_u32(&bytes[0..1]), 0x00000001);
    assert_eq!(to_u32(&bytes[3..5]), 0x00006789);
    assert_eq!(to_u32(&bytes[1..4]), 0x00234567);
    assert_eq!(to_u32(&bytes[4..]), 0x89abcdef);
  }

  #[test]
  fn test_extend_sign() {
    assert_eq!(extend_sign(32, 6), -32);
    assert_eq!(extend_sign(31, 6), 31);
    assert_eq!(extend_sign(128, 8), -128);
    assert_eq!(extend_sign(127, 8), 127);

    assert_eq!(extend_sign(2048, 12), -2048);
    assert_eq!(extend_sign(2047, 12), 2047);
    assert_eq!(extend_sign(32768, 16), -32768);
    assert_eq!(extend_sign(32767, 16), 32767);

    assert_eq!(extend_sign(8388608, 24), -8388608);
    assert_eq!(extend_sign(8388607, 24), 8388607);
    assert_eq!(extend_sign(2147483648, 32), -2147483648);
    assert_eq!(extend_sign(2147483647, 32), 2147483647);
  }
}
<|endoftext|>


<commit_before>use std::borrow::Cow;
use std::fs;
use std::io::{BufRead, BufReader};
use std::time::Duration;

use anylog;
use chrono::Utc;
use failure::{Error, ResultExt};
use regex::Regex;
use sentry::protocol::{Breadcrumb, ClientSdkInfo, Event};
use sentry::{Client, ClientOptions, Dsn};

use constants::USER_AGENT;

lazy_static! {
    static ref COMPONENT_RE: Regex = Regex::new(r#"^([^:]+): (.*)$"#).unwrap();
}

/// Attaches all logs from a logfile as breadcrumbs to the given event.
pub fn attach_logfile(event: &mut Event, logfile: &str, with_component: bool) -> Result<(), Error> {
    let f = fs::File::open(logfile).context("Could not open logfile")?;

    // sentry currently requires timestamps for breadcrumbs at all times.
    // Because we might not be able to parse a timestamp from the log file
    // we fall back to either the modified time of the file or if that does
    // not work we use the current timestamp.
    let fallback_timestamp = fs::metadata(logfile)
        .context("Could not get metadata for logfile")?
        .modified()
        .map(|ts| ts.into())
        .unwrap_or_else(|_| Utc::now());

    let reader = BufReader::new(f);
    for line in reader.lines() {
        let line = line?;
        let rec = anylog::LogEntry::parse(line.as_bytes());
        let component;
        let message;

        if_chain! {
            if with_component;
            if let Some(caps) = COMPONENT_RE.captures(&rec.message());
            then {
                component = caps.get(1).map(|x| x.as_str().to_string()).unwrap();
                message = caps.get(2).map(|x| x.as_str().to_string()).unwrap();
            } else {
                component = "log".to_string();
                message = rec.message().to_string();
            }
        }

        event.breadcrumbs.push(Breadcrumb {
            timestamp: rec.utc_timestamp().unwrap_or(fallback_timestamp),
            message: Some(message),
            category: Some(component.to_string()),
            ..Default::default()
        })
    }

    if event.breadcrumbs.len() > 100 {
        let skip = event.breadcrumbs.len() - 100;
        event.breadcrumbs.drain(..skip);
    }

    Ok(())
}

/// Returns SDK information for sentry-cli.
pub fn get_sdk_info() -> Cow<'static, ClientSdkInfo> {
    Cow::Owned(ClientSdkInfo {
        name: env!("CARGO_PKG_NAME").into(),
        version: env!("CARGO_PKG_VERSION").into(),
        integrations: Vec::new(),
    })
}

/// Executes the callback with an isolate sentry client on an empty isolate scope.
///
/// Use the client's API to capture exceptions or manual events. The client will automatically drop
/// after the callback has finished and drain its queue with a timeout of 2 seconds.
///
/// You can optionally return a value from the callback which will also be the return value of this
/// function if draining the queue is successful. On error, the return value will be None.
pub fn with_sentry_client<F, R>(dsn: Dsn, callback: F) -> Option<R>
where
    F: FnOnce(&Client) -> R,
{
    let client = Client::with_dsn_and_options(dsn, ClientOptions {
        user_agent: USER_AGENT.into(),
        ..Default::default()
    });

    let rv = callback(&client);
    if client.drain_events(Some(Duration::from_secs(2))) {
        Some(rv)
    } else {
        None
    }
}
<commit_msg>style: Run rustfmt again<commit_after>use std::borrow::Cow;
use std::fs;
use std::io::{BufRead, BufReader};
use std::time::Duration;

use anylog;
use chrono::Utc;
use failure::{Error, ResultExt};
use regex::Regex;
use sentry::protocol::{Breadcrumb, ClientSdkInfo, Event};
use sentry::{Client, ClientOptions, Dsn};

use constants::USER_AGENT;

lazy_static! {
    static ref COMPONENT_RE: Regex = Regex::new(r#"^([^:]+): (.*)$"#).unwrap();
}

/// Attaches all logs from a logfile as breadcrumbs to the given event.
pub fn attach_logfile(event: &mut Event, logfile: &str, with_component: bool) -> Result<(), Error> {
    let f = fs::File::open(logfile).context("Could not open logfile")?;

    // sentry currently requires timestamps for breadcrumbs at all times.
    // Because we might not be able to parse a timestamp from the log file
    // we fall back to either the modified time of the file or if that does
    // not work we use the current timestamp.
    let fallback_timestamp = fs::metadata(logfile)
        .context("Could not get metadata for logfile")?
        .modified()
        .map(|ts| ts.into())
        .unwrap_or_else(|_| Utc::now());

    let reader = BufReader::new(f);
    for line in reader.lines() {
        let line = line?;
        let rec = anylog::LogEntry::parse(line.as_bytes());
        let component;
        let message;

        if_chain! {
            if with_component;
            if let Some(caps) = COMPONENT_RE.captures(&rec.message());
            then {
                component = caps.get(1).map(|x| x.as_str().to_string()).unwrap();
                message = caps.get(2).map(|x| x.as_str().to_string()).unwrap();
            } else {
                component = "log".to_string();
                message = rec.message().to_string();
            }
        }

        event.breadcrumbs.push(Breadcrumb {
            timestamp: rec.utc_timestamp().unwrap_or(fallback_timestamp),
            message: Some(message),
            category: Some(component.to_string()),
            ..Default::default()
        })
    }

    if event.breadcrumbs.len() > 100 {
        let skip = event.breadcrumbs.len() - 100;
        event.breadcrumbs.drain(..skip);
    }

    Ok(())
}

/// Returns SDK information for sentry-cli.
pub fn get_sdk_info() -> Cow<'static, ClientSdkInfo> {
    Cow::Owned(ClientSdkInfo {
        name: env!("CARGO_PKG_NAME").into(),
        version: env!("CARGO_PKG_VERSION").into(),
        integrations: Vec::new(),
    })
}

/// Executes the callback with an isolate sentry client on an empty isolate scope.
///
/// Use the client's API to capture exceptions or manual events. The client will automatically drop
/// after the callback has finished and drain its queue with a timeout of 2 seconds.
///
/// You can optionally return a value from the callback which will also be the return value of this
/// function if draining the queue is successful. On error, the return value will be None.
pub fn with_sentry_client<F, R>(dsn: Dsn, callback: F) -> Option<R>
where
    F: FnOnce(&Client) -> R,
{
    let client = Client::with_dsn_and_options(
        dsn,
        ClientOptions {
            user_agent: USER_AGENT.into(),
            ..Default::default()
        },
    );

    let rv = callback(&client);
    if client.drain_events(Some(Duration::from_secs(2))) {
        Some(rv)
    } else {
        None
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

//! Utilities for providing the goto definition feature

use crate::{
    location::read_contents_and_get_lsp_location_of_graphql_literal,
    lsp_runtime_error::{LSPRuntimeError, LSPRuntimeResult},
    node_resolution_info::NodeKind,
    node_resolution_info::NodeResolutionInfo,
    server::GlobalState,
    utils::span_to_range_offset,
};
use common::Location as IRLocation;
use graphql_ir::{FragmentSpread, Program, Visitor};
use intern::string_key::StringKey;
use lsp_types::{
    request::{References, Request},
    Location as LSPLocation, Range,
};
use std::path::PathBuf;

fn get_references_response(
    node_resolution_info: NodeResolutionInfo,
    program: &Program,
    root_dir: &PathBuf,
) -> LSPRuntimeResult<Vec<LSPLocation>> {
    match node_resolution_info.kind {
        NodeKind::FragmentDefinition(fragment) => {
            let references =
                ReferenceFinder::get_references_to_fragment(program, fragment.name.value)
                    .into_iter()
                    .map(|location| transform_ir_location_to_lsp_location(root_dir, location))
                    .collect::<Result<Vec<_>, LSPRuntimeError>>()?;

            Ok(references)
        }
        _ => Err(LSPRuntimeError::ExpectedError),
    }
}

/// Given a root dir and a graphql_ir::Location, return a Result containing an
/// LSPLocation (i.e. lsp_types::Location).
///
/// IR Locations contain a description of where to find the graphql literal,
/// which can be embedded, standalone or generated; and the span of the ir node.
/// The IR Location's span contains the start and end character of the node.
///
/// LSP Locations contain a file URI and a pair of row/column offsets, and are
/// the formatted expected by the LSP Client (i.e. VSCode).
///
/// In order to convert from an IR Location to an LSP location, this function:
/// - reads the file containing the literal, extracts it, and gets the LSP Location
///   of the literal
/// - converts the IR Location's span to a range offset. Given the text of a literal,
///   convert the start/end characters to a pair of ("move over X characters" OR
///   "move down X lines and move to character Y")
/// - add this range offset to the LSP location's start, giving us the LSP location
///   of the IR node.
fn transform_ir_location_to_lsp_location(
    root_dir: &PathBuf,
    node_ir_location: IRLocation,
) -> LSPRuntimeResult<LSPLocation> {
    let (graphql_literal_text, lsp_location_of_graphql_literal) =
        read_contents_and_get_lsp_location_of_graphql_literal(node_ir_location, root_dir)?;

    let range_offset = span_to_range_offset(*node_ir_location.span(), &graphql_literal_text)
        .ok_or(LSPRuntimeError::ExpectedError)?;

    let mut lsp_location_of_node = lsp_location_of_graphql_literal;
    // update lsp_location_of_node to have a range that points to the ir node
    lsp_location_of_node.range = Range {
        start: lsp_location_of_node.range.start + range_offset.start,
        end: lsp_location_of_node.range.start + range_offset.end,
    };
    Ok(lsp_location_of_node)
}

#[derive(Debug, Clone)]
struct ReferenceFinder {
    references: Vec<IRLocation>,
    name: StringKey,
}

impl ReferenceFinder {
    fn get_references_to_fragment(program: &Program, name: StringKey) -> Vec<IRLocation> {
        let mut reference_finder = ReferenceFinder {
            references: vec![],
            name,
        };
        reference_finder.visit_program(program);
        reference_finder.references
    }
}

impl Visitor for ReferenceFinder {
    const NAME: &'static str = "ReferenceFinder";
    const VISIT_ARGUMENTS: bool = false;
    const VISIT_DIRECTIVES: bool = false;

    fn visit_fragment_spread(&mut self, spread: &FragmentSpread) {
        if spread.fragment.item == self.name {
            self.references.push(spread.fragment.location);
        }
    }
}

pub(crate) fn on_references(
    state: &impl GlobalState,
    params: <References as Request>::Params,
) -> LSPRuntimeResult<<References as Request>::Result> {
    let node_resolution_info = state.resolve_node(&params.text_document_position)?;
    let references_response = get_references_response(
        node_resolution_info,
        &state
            .get_program(&state.extract_project_name_from_url(
                &params.text_document_position.text_document.uri,
            )?)?,
        &state.root_dir(),
    )?;
    Ok(Some(references_response))
}
<commit_msg>Fix transform_reference_locations_to_lsp_locations<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

//! Utilities for providing the goto definition feature

use crate::{
    location::read_contents_and_get_lsp_location_of_graphql_literal,
    lsp_runtime_error::{LSPRuntimeError, LSPRuntimeResult},
    node_resolution_info::NodeKind,
    node_resolution_info::NodeResolutionInfo,
    server::GlobalState,
    utils::span_to_range_offset,
};
use common::{Location as IRLocation, SourceLocationKey};
use graphql_ir::{FragmentSpread, Program, Visitor};
use intern::string_key::StringKey;
use lsp_types::{
    request::{References, Request},
    Location as LSPLocation, Range,
};
use std::path::PathBuf;

fn get_references_response(
    node_resolution_info: NodeResolutionInfo,
    program: &Program,
    root_dir: &PathBuf,
) -> LSPRuntimeResult<Vec<LSPLocation>> {
    match node_resolution_info.kind {
        NodeKind::FragmentDefinition(fragment) => {
            let references =
                ReferenceFinder::get_references_to_fragment(program, fragment.name.value)
                    .into_iter()
                    .map(|location| transform_ir_location_to_lsp_location(root_dir, location))
                    .collect::<Result<Vec<_>, LSPRuntimeError>>()?;

            Ok(references)
        }
        _ => Err(LSPRuntimeError::ExpectedError),
    }
}

/// Given a root dir and a graphql_ir::Location, return a Result containing an
/// LSPLocation (i.e. lsp_types::Location).
///
/// IR Locations contain a description of where to find the graphql literal,
/// which can be embedded, standalone or generated; and the span of the ir node.
/// The IR Location's span contains the start and end character of the node.
///
/// LSP Locations contain a file URI and a pair of row/column offsets, and are
/// the formatted expected by the LSP Client (i.e. VSCode).
///
/// In order to convert from an IR Location to an LSP location, this function:
/// - reads the file containing the literal, extracts it, and gets the LSP Location
///   of the literal
/// - converts the IR Location's span to a range offset. Given the text of a literal,
///   convert the start/end characters to a pair of ("move over X characters" OR
///   "move down X lines and move to character Y")
/// - add this range offset to the LSP location's start, giving us the LSP location
///   of the IR node.
fn transform_ir_location_to_lsp_location(
    root_dir: &PathBuf,
    node_ir_location: IRLocation,
) -> LSPRuntimeResult<LSPLocation> {
    let (graphql_literal_text, lsp_location_of_graphql_literal) =
        read_contents_and_get_lsp_location_of_graphql_literal(node_ir_location, root_dir)?;

    // Case 1: for the standalone file, the lsp_location_of_graphql_literal is the result of what we need
    if let SourceLocationKey::Standalone { .. } = node_ir_location.source_location() {
        return Ok(lsp_location_of_graphql_literal);
    }

    // Case 2: for the embedded source, the lsp_location_of_graphql_literal should be swifted by the span range.
    let range_offset = span_to_range_offset(*node_ir_location.span(), &graphql_literal_text)
        .ok_or(LSPRuntimeError::ExpectedError)?;

    let mut lsp_location_of_node = lsp_location_of_graphql_literal;
    // update lsp_location_of_node to have a range that points to the ir node
    lsp_location_of_node.range = Range {
        start: lsp_location_of_node.range.start + range_offset.start,
        end: lsp_location_of_node.range.start + range_offset.end,
    };
    Ok(lsp_location_of_node)
}

#[derive(Debug, Clone)]
struct ReferenceFinder {
    references: Vec<IRLocation>,
    name: StringKey,
}

impl ReferenceFinder {
    fn get_references_to_fragment(program: &Program, name: StringKey) -> Vec<IRLocation> {
        let mut reference_finder = ReferenceFinder {
            references: vec![],
            name,
        };
        reference_finder.visit_program(program);
        reference_finder.references
    }
}

impl Visitor for ReferenceFinder {
    const NAME: &'static str = "ReferenceFinder";
    const VISIT_ARGUMENTS: bool = false;
    const VISIT_DIRECTIVES: bool = false;

    fn visit_fragment_spread(&mut self, spread: &FragmentSpread) {
        if spread.fragment.item == self.name {
            self.references.push(spread.fragment.location);
        }
    }
}

pub(crate) fn on_references(
    state: &impl GlobalState,
    params: <References as Request>::Params,
) -> LSPRuntimeResult<<References as Request>::Result> {
    let node_resolution_info = state.resolve_node(&params.text_document_position)?;
    let references_response = get_references_response(
        node_resolution_info,
        &state
            .get_program(&state.extract_project_name_from_url(
                &params.text_document_position.text_document.uri,
            )?)?,
        &state.root_dir(),
    )?;
    Ok(Some(references_response))
}
<|endoftext|>


<commit_before>//! A pass that checks to make sure private fields and methods aren't used
//! outside their scopes. This pass will also generate a set of exported items
//! which are available for use externally when compiled as a library.

use rustc_data_structures::fx::FxHashMap;
use rustc_hir::HirId;
use rustc_macros::HashStable;
use std::fmt;
use std::hash::Hash;

// Accessibility levels, sorted in ascending order
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, HashStable)]
pub enum AccessLevel {
    /// Superset of `AccessLevel::Reachable` used to mark impl Trait items.
    ReachableFromImplTrait,
    /// Exported items + items participating in various kinds of public interfaces,
    /// but not directly nameable. For example, if function `fn f() -> T {...}` is
    /// public, then type `T` is reachable. Its values can be obtained by other crates
    /// even if the type itself is not nameable.
    Reachable,
    /// Public items + items accessible to other crates with help of `pub use` re-exports
    Exported,
    /// Items accessible to other crates directly, without help of re-exports
    Public,
}

// Accessibility levels for reachable HIR nodes
#[derive(Clone)]
pub struct AccessLevels<Id = HirId> {
    pub map: FxHashMap<Id, AccessLevel>,
}

impl<Id: Hash + Eq> AccessLevels<Id> {
    /// See `AccessLevel::Reachable`.
    pub fn is_reachable(&self, id: Id) -> bool {
        self.map.get(&id) >= Some(&AccessLevel::Reachable)
    }

    /// See `AccessLevel::Exported`.
    pub fn is_exported(&self, id: Id) -> bool {
        self.map.get(&id) >= Some(&AccessLevel::Exported)
    }

    /// See `AccessLevel::Public`.
    pub fn is_public(&self, id: Id) -> bool {
        self.map.get(&id) >= Some(&AccessLevel::Public)
    }
}

impl<Id: Hash + Eq> Default for AccessLevels<Id> {
    fn default() -> Self {
        AccessLevels { map: Default::default() }
    }
}

impl<Id: Hash + Eq + fmt::Debug> fmt::Debug for AccessLevels<Id> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Debug::fmt(&self.map, f)
    }
}
<commit_msg>docs: Edit rustc_middle::middle::privacy<commit_after>//! A pass that checks to make sure private fields and methods aren't used
//! outside their scopes. This pass will also generate a set of exported items
//! which are available for use externally when compiled as a library.

use rustc_data_structures::fx::FxHashMap;
use rustc_hir::HirId;
use rustc_macros::HashStable;
use std::fmt;
use std::hash::Hash;

/// Represents the levels of accessibility an item can have.
///
/// The variants are sorted in ascending order of accessibility.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, HashStable)]
pub enum AccessLevel {
    /// Superset of `AccessLevel::Reachable` used to mark impl Trait items.
    ReachableFromImplTrait,
    /// Exported items + items participating in various kinds of public interfaces,
    /// but not directly nameable. For example, if function `fn f() -> T {...}` is
    /// public, then type `T` is reachable. Its values can be obtained by other crates
    /// even if the type itself is not nameable.
    Reachable,
    /// Public items + items accessible to other crates with the help of `pub use` re-exports.
    Exported,
    /// Items accessible to other crates directly, without the help of re-exports.
    Public,
}

/// Holds a map of accessibility levels for reachable HIR nodes.
#[derive(Clone)]
pub struct AccessLevels<Id = HirId> {
    pub map: FxHashMap<Id, AccessLevel>,
}

impl<Id: Hash + Eq> AccessLevels<Id> {
    /// See `AccessLevel::Reachable`.
    pub fn is_reachable(&self, id: Id) -> bool {
        self.map.get(&id) >= Some(&AccessLevel::Reachable)
    }

    /// See `AccessLevel::Exported`.
    pub fn is_exported(&self, id: Id) -> bool {
        self.map.get(&id) >= Some(&AccessLevel::Exported)
    }

    /// See `AccessLevel::Public`.
    pub fn is_public(&self, id: Id) -> bool {
        self.map.get(&id) >= Some(&AccessLevel::Public)
    }
}

impl<Id: Hash + Eq> Default for AccessLevels<Id> {
    fn default() -> Self {
        AccessLevels { map: Default::default() }
    }
}

impl<Id: Hash + Eq + fmt::Debug> fmt::Debug for AccessLevels<Id> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Debug::fmt(&self.map, f)
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate log;

use crate::error::Result;
use clap::{App,
           Arg};
use env_logger;
use habitat_butterfly::rumor::{dat_file,
                               Departure,
                               Election,
                               ElectionUpdate,
                               Service,
                               ServiceConfig,
                               ServiceFile};
use log::error;
use std::{path::Path,
          process};

pub mod error;

fn main() {
    env_logger::init();
    let matches =
        App::new("Habitat RST Reader").about("Introspection for the butterfly RST file")
                                      .arg(Arg::with_name("FILE").required(true)
                                                                 .index(1)
                                                                 .help("Path to the RST file"))
                                      .arg(Arg::with_name("STATS").short("s")
                                                                  .long("stats")
                                                                  .conflicts_with("FOLLOW")
                                                                  .help("Display statistics \
                                                                         about the contents of \
                                                                         the file"))
                                      .get_matches();

    let file = matches.value_of("FILE").unwrap();
    let stats = matches.is_present("STATS");

    let path = Path::new(file);
    let dat_file = match dat_file::DatFile::new(path.to_path_buf()) {
        Ok(d) => d,
        Err(e) => {
            error!("Could not read dat file: {:?}", e);
            process::exit(1);
        }
    };

    let result = if stats {
        output_stats(dat_file)
    } else {
        output_rumors(dat_file)
    };

    if result.is_err() {
        error!("Error processing dat file: {:?}", result);
        process::exit(1);
    }
}

fn output_rumors(mut dat_file: dat_file::DatFile) -> Result<()> {
    let mut version = [0; 1];

    dat_file.read_header(&mut version)?;

    for member in dat_file.read_members()? {
        println!("{}", member);
    }

    for service in dat_file.read_rumors::<Service>(dat_file.service_len())? {
        println!("{}", service);
    }

    for service_config in dat_file.read_rumors::<ServiceConfig>(dat_file.service_config_len())? {
        println!("{}", service_config);
    }

    for service_file in dat_file.read_rumors::<ServiceFile>(dat_file.service_file_len())? {
        println!("{}", service_file);
    }

    for election in dat_file.read_rumors::<Election>(dat_file.election_len())? {
        println!("{}", election);
    }

    for update_election in dat_file.read_rumors::<ElectionUpdate>(dat_file.update_len())? {
        println!("{}", update_election);
    }

    if version[0] >= 2 {
        for departure in dat_file.read_rumors::<Departure>(dat_file.departure_len())? {
            println!("{}", departure);
        }
    }

    Ok(())
}

fn output_stats(mut dat_file: dat_file::DatFile) -> Result<()> {
    let mut membership = 0;
    let mut services = 0;
    let mut service_configs = 0;
    let mut service_files = 0;
    let mut elections = 0;
    let mut update_elections = 0;
    let mut departures = 0;

    let mut version = [0; 1];

    dat_file.read_header(&mut version)?;
    membership += dat_file.read_members()?.len();

    services += dat_file.read_rumors::<Service>(dat_file.service_len())?
                        .len();
    service_configs += dat_file.read_rumors::<ServiceConfig>(dat_file.service_config_len())?
                               .len();
    service_files += dat_file.read_rumors::<ServiceFile>(dat_file.service_file_len())?
                             .len();
    elections += dat_file.read_rumors::<Election>(dat_file.election_len())?
                         .len();
    update_elections += dat_file.read_rumors::<ElectionUpdate>(dat_file.update_len())?
                                .len();

    if version[0] >= 2 {
        departures += dat_file.read_rumors::<Departure>(dat_file.departure_len())?
                              .len();
    }

    println!("Summary:");
    println!("");
    println!("Membership: {}", membership);
    println!("Services: {}", services);
    println!("Service Configs: {}", service_configs);
    println!("Service Files: {}", service_files);
    println!("Elections: {}", elections);
    println!("Update Elections: {}", update_elections);
    println!("Departures: {}", departures);

    Ok(())
}
<commit_msg>Fix clippy lint<commit_after>#[macro_use]
extern crate log;

use crate::error::Result;
use clap::{App,
           Arg};
use env_logger;
use habitat_butterfly::rumor::{dat_file,
                               Departure,
                               Election,
                               ElectionUpdate,
                               Service,
                               ServiceConfig,
                               ServiceFile};
use log::error;
use std::{path::Path,
          process};

pub mod error;

fn main() {
    env_logger::init();
    let matches =
        App::new("Habitat RST Reader").about("Introspection for the butterfly RST file")
                                      .arg(Arg::with_name("FILE").required(true)
                                                                 .index(1)
                                                                 .help("Path to the RST file"))
                                      .arg(Arg::with_name("STATS").short("s")
                                                                  .long("stats")
                                                                  .conflicts_with("FOLLOW")
                                                                  .help("Display statistics \
                                                                         about the contents of \
                                                                         the file"))
                                      .get_matches();

    let file = matches.value_of("FILE").unwrap();
    let stats = matches.is_present("STATS");

    let path = Path::new(file);
    let dat_file = match dat_file::DatFile::new(path.to_path_buf()) {
        Ok(d) => d,
        Err(e) => {
            error!("Could not read dat file: {:?}", e);
            process::exit(1);
        }
    };

    let result = if stats {
        output_stats(dat_file)
    } else {
        output_rumors(dat_file)
    };

    if result.is_err() {
        error!("Error processing dat file: {:?}", result);
        process::exit(1);
    }
}

fn output_rumors(mut dat_file: dat_file::DatFile) -> Result<()> {
    let mut version = [0; 1];

    dat_file.read_header(&mut version)?;

    for member in dat_file.read_members()? {
        println!("{}", member);
    }

    for service in dat_file.read_rumors::<Service>(dat_file.service_len())? {
        println!("{}", service);
    }

    for service_config in dat_file.read_rumors::<ServiceConfig>(dat_file.service_config_len())? {
        println!("{}", service_config);
    }

    for service_file in dat_file.read_rumors::<ServiceFile>(dat_file.service_file_len())? {
        println!("{}", service_file);
    }

    for election in dat_file.read_rumors::<Election>(dat_file.election_len())? {
        println!("{}", election);
    }

    for update_election in dat_file.read_rumors::<ElectionUpdate>(dat_file.update_len())? {
        println!("{}", update_election);
    }

    if version[0] >= 2 {
        for departure in dat_file.read_rumors::<Departure>(dat_file.departure_len())? {
            println!("{}", departure);
        }
    }

    Ok(())
}

fn output_stats(mut dat_file: dat_file::DatFile) -> Result<()> {
    let mut membership = 0;
    let mut services = 0;
    let mut service_configs = 0;
    let mut service_files = 0;
    let mut elections = 0;
    let mut update_elections = 0;
    let mut departures = 0;

    let mut version = [0; 1];

    dat_file.read_header(&mut version)?;
    membership += dat_file.read_members()?.len();

    services += dat_file.read_rumors::<Service>(dat_file.service_len())?
                        .len();
    service_configs += dat_file.read_rumors::<ServiceConfig>(dat_file.service_config_len())?
                               .len();
    service_files += dat_file.read_rumors::<ServiceFile>(dat_file.service_file_len())?
                             .len();
    elections += dat_file.read_rumors::<Election>(dat_file.election_len())?
                         .len();
    update_elections += dat_file.read_rumors::<ElectionUpdate>(dat_file.update_len())?
                                .len();

    if version[0] >= 2 {
        departures += dat_file.read_rumors::<Departure>(dat_file.departure_len())?
                              .len();
    }

    println!("Summary:");
    println!();
    println!("Membership: {}", membership);
    println!("Services: {}", services);
    println!("Service Configs: {}", service_configs);
    println!("Service Files: {}", service_files);
    println!("Elections: {}", elections);
    println!("Update Elections: {}", update_elections);
    println!("Departures: {}", departures);

    Ok(())
}
<|endoftext|>