<commit_before>// Copyright 2021 Google LLC
//
// 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
//
//    https://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.

use autocxx::subclass::prelude::*;
use autocxx::{c_int, PinMut};
use std::cell::{Ref, RefCell, RefMut};
use std::ops::Deref;
use std::pin::Pin;
use std::rc::Rc;

use crate::ffi;

/// A memory-safe handle to a C++ RenderFrameHost.
///
/// This is a toy, hypothetical, example.
///
/// Creation: in this sample, the only option is to use [`RenderFrameHostHandle::from_id`]
/// which corresponds to the equivalent method in C++ `RenderFrameHost`. Unlike
/// the C++ version, you must pass a WebContents so that Rust wrappers can listen for
/// destruction events.
///
/// The returned handle is memory safe and can be used to access the methods
/// of [`ffi::content::RenderFrameHost`]. To use such a method, you have three options:
/// * If you believe there is no chance that the `RenderFrameHost` has been
///   destroyed, and if the method is const, you can just go ahead and call methods
///   on this object. As it implements [`std::ops::Deref`], that will just work -
///   but your code will panic if the `RenderFrameHost` was already destroyed.
/// * If the method is non-const, you'll have to call `.pin_mut().method()` instead
//    but otherwise this is functionally identical.
/// * If you believe that there is a chance that the `RenderFrameHost` was already
///   destroyed, use [`RenderFrameHostHandle::try_borrow`] or
///   [`RenderFrameHostHandle::try_borrow_mut`]. This will return
///   a guard object which guarantees the existence of the `RenderFrameHost`
///   during its lifetime.
///
/// # Performance characteristics
///
/// The existence of this object registers an observer with the `WebContents`
/// and deregisters it on destruction. That is, of course, an overhead, but
/// that's necessary to keep track of liveness. (A more efficient
/// implementation would use a single observer for multiple such handles - but
/// this is a toy implementation).
///
/// In addition, each time you extract the value from this
/// `RenderFrameHostHandle`, a liveness check is performed. This involves
///
/// If you're going to access the `RenderFrameHost` multiple times, it's
/// advised that you call [`RenderFrameHostHandle::try_borrow`] or
/// [`RenderFrameHostHandle::try_borrow_mut`] and then use
/// the result multiple times. The liveness check for the `RenderFrameHost`
/// will be performed only once at runtime.
///
/// # Destruction of RenderFrameHosts while borrowed
///
/// If you have called [`RenderFrameHostHandle::try_borrow`] (or its mutable
/// equivalent) and still have an outstanding borrow, any code path - via C++
/// - which results it the destruction of the `RenderFrameHost` will result in
/// a runtime panic.
pub struct RenderFrameHostHandle<'wc> {
    obs: Rc<RefCell<RenderFrameHostForWebContents>>,
    web_contents: Pin<&'wc mut ffi::content::WebContents>,
}

impl<'wc> RenderFrameHostHandle<'wc> {
    /// Create a memory-safe handle to a RenderFrameHost using its
    /// process ID and frame ID.
    pub fn from_id(
        render_process_id: c_int,
        render_frame_id: c_int,
        mut web_contents: Pin<&'wc mut ffi::content::WebContents>,
    ) -> Self {
        // Instantiate our WebContentsObserver subclass.
        let obs = RenderFrameHostForWebContents::new_rust_owned(RenderFrameHostForWebContents {
            rfh: ffi::content::RenderFrameHost::FromId(render_process_id, render_frame_id),
            cpp_peer: Default::default(),
        });

        // And now register it.
        // This nasty line will go away when autocxx is a bit more sophisticated.
        let superclass_ptr = cast_to_superclass(obs.as_ref().borrow_mut().peer_mut());

        // But this will remain unsafe. cxx policy is that any raw pointer
        // passed into a C++ function requires an unsafe {} block and that
        // is sensible. We may of course provide an ergonomic Rust wrapper
        // around WebContents which provides safe Rust equivalents
        // (using references or similar rather than pointers) in which case
        // this unsafe block would go away.
        unsafe { web_contents.as_mut().AddObserver(superclass_ptr) };

        Self { obs, web_contents }
    }

    /// Tries to return a mutable reference to the RenderFrameHost.
    /// Because this requires `self` to be `&mut`, and that lifetime is
    /// applied to the returned `RenderFrameHost`, the compiler will prevent
    /// multiple such references existing in Rust at the same time.
    /// This will return `None` if the RenderFrameHost were already destroyed.
    pub fn try_borrow_mut<'a>(
        &'a mut self,
    ) -> Option<impl PinMut<ffi::content::RenderFrameHost> + 'a> {
        let ref_mut = self.obs.as_ref().borrow_mut();
        if ref_mut.rfh.is_null() {
            None
        } else {
            Some(RenderFrameHostRefMut(ref_mut))
        }
    }

    /// Tries to return a reference to the RenderFrameHost.
    /// The compiler will prevent calls to this if anyone has an outstanding
    /// mutable reference from [`RenderFrameHostHandle::try_borrow_mut`].
    /// This will return `None` if the RenderFrameHost were already destroyed.
    #[allow(dead_code)]
    pub fn try_borrow<'a>(&'a self) -> Option<impl AsRef<ffi::content::RenderFrameHost> + 'a> {
        let ref_non_mut = self.obs.as_ref().borrow();
        if ref_non_mut.rfh.is_null() {
            None
        } else {
            Some(RenderFrameHostRef(ref_non_mut))
        }
    }
}

impl<'wc> Drop for RenderFrameHostHandle<'wc> {
    fn drop(&mut self) {
        // Unregister our observer.
        let superclass_ptr = cast_to_superclass(self.obs.as_ref().borrow_mut().peer_mut());
        unsafe { self.web_contents.as_mut().RemoveObserver(superclass_ptr) };
    }
}

impl<'wc> AsRef<ffi::content::RenderFrameHost> for RenderFrameHostHandle<'wc> {
    fn as_ref(&self) -> &ffi::content::RenderFrameHost {
        let ref_non_mut = self.obs.as_ref().borrow();
        // Safety: the .rfh field is guaranteed to be a RenderFrameHost
        // and we are observing its lifetime so it will be reset to null
        // if destroyed.
        unsafe { ref_non_mut.rfh.as_ref() }.expect("This RenderFrameHost was already destroyed")
    }
}

impl<'wc> PinMut<ffi::content::RenderFrameHost> for RenderFrameHostHandle<'wc> {
    fn pin_mut(&mut self) -> Pin<&mut ffi::content::RenderFrameHost> {
        let ref_mut = self.obs.as_ref().borrow_mut();
        // Safety: the .rfh field is guaranteed to be a RenderFrameHost
        // and we are observing its lifetime so it will be reset to null
        // if destroyed.
        unsafe { ref_mut.rfh.as_mut().map(|p| Pin::new_unchecked(p)) }
            .expect("This RenderFrameHost was already destroyed")
    }
}

impl<'wc> Deref for RenderFrameHostHandle<'wc> {
    type Target = ffi::content::RenderFrameHost;
    fn deref(&self) -> &Self::Target {
        self.as_ref()
    }
}

#[doc(hidden)]
struct RenderFrameHostRefMut<'a>(RefMut<'a, RenderFrameHostForWebContents>);

#[doc(hidden)]
struct RenderFrameHostRef<'a>(Ref<'a, RenderFrameHostForWebContents>);

impl<'a> AsRef<ffi::content::RenderFrameHost> for RenderFrameHostRef<'a> {
    fn as_ref(&self) -> &ffi::content::RenderFrameHost {
        // Safety:
        // Creation precondition is that self.0.rfh is not null
        // and it can't be destroyed whilst this borrow exists.
        unsafe { self.0.rfh.as_ref().unwrap() }
    }
}

impl<'a> PinMut<ffi::content::RenderFrameHost> for RenderFrameHostRefMut<'a> {
    fn pin_mut(&mut self) -> Pin<&mut ffi::content::RenderFrameHost> {
        // Safety:
        // Creation precondition is that self.0.rfh is not null
        // and it can't be destroyed whilst this borrow exists.
        unsafe { Pin::new_unchecked(self.0.rfh.as_mut().unwrap()) }
    }
}

impl<'a> AsRef<ffi::content::RenderFrameHost> for RenderFrameHostRefMut<'a> {
    fn as_ref(&self) -> &ffi::content::RenderFrameHost {
        // Safety:
        // Creation precondition is that self.0.rfh is not null
        // and it can't be destroyed whilst this borrow exists.
        unsafe { self.0.rfh.as_ref().unwrap() }
    }
}

impl<'a> Deref for RenderFrameHostRef<'a> {
    type Target = ffi::content::RenderFrameHost;
    fn deref(&self) -> &Self::Target {
        self.as_ref()
    }
}

impl<'a> Deref for RenderFrameHostRefMut<'a> {
    type Target = ffi::content::RenderFrameHost;
    fn deref(&self) -> &Self::Target {
        self.as_ref()
    }
}

#[is_subclass(superclass("content::WebContentsObserver"))]
#[doc(hidden)]
pub struct RenderFrameHostForWebContents {
    rfh: *mut ffi::content::RenderFrameHost,
}

impl ffi::content::WebContentsObserver_methods for RenderFrameHostForWebContents {
    unsafe fn RenderFrameDeleted(&mut self, destroyed_rfh: *mut ffi::content::RenderFrameHost) {
        if self.rfh == destroyed_rfh {
            self.rfh = std::ptr::null_mut()
        }
    }
}

fn cast_to_superclass(
    obs: Pin<&mut ffi::RenderFrameHostForWebContentsCpp>,
) -> *mut ffi::content::WebContentsObserver {
    // This horrid code will all go away once we implement
    // https://github.com/google/autocxx/issues/592; safe wrappers will
    // be automatically generated to allow upcasting to superclasses.
    // NB this code is probably actually _wrong_ too meanwhile; we need to cast
    // on the C++ side.
    let subclass_obs_ptr =
        unsafe { Pin::into_inner_unchecked(obs) } as *mut ffi::RenderFrameHostForWebContentsCpp;
    unsafe {
        std::mem::transmute::<
            *mut ffi::RenderFrameHostForWebContentsCpp,
            *mut ffi::content::WebContentsObserver,
        >(subclass_obs_ptr)
    }
}
<commit_msg>Update render_frame_host.rs<commit_after>// Copyright 2021 Google LLC
//
// 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
//
//    https://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.

use autocxx::subclass::prelude::*;
use autocxx::{c_int, PinMut};
use std::cell::{Ref, RefCell, RefMut};
use std::ops::Deref;
use std::pin::Pin;
use std::rc::Rc;

use crate::ffi;

/// A memory-safe handle to a C++ RenderFrameHost.
///
/// This is a toy, hypothetical, example.
///
/// Creation: in this sample, the only option is to use [`RenderFrameHostHandle::from_id`]
/// which corresponds to the equivalent method in C++ `RenderFrameHost`. Unlike
/// the C++ version, you must pass a WebContents so that Rust wrappers can listen for
/// destruction events.
///
/// The returned handle is memory safe and can be used to access the methods
/// of [`ffi::content::RenderFrameHost`]. To use such a method, you have three options:
/// * If you believe there is no chance that the `RenderFrameHost` has been
///   destroyed, and if the method is const, you can just go ahead and call methods
///   on this object. As it implements [`std::ops::Deref`], that will just work -
///   but your code will panic if the `RenderFrameHost` was already destroyed.
/// * If the method is non-const, you'll have to call `.pin_mut().method()` instead
//    but otherwise this is functionally identical.
/// * If you believe that there is a chance that the `RenderFrameHost` was already
///   destroyed, use [`RenderFrameHostHandle::try_borrow`] or
///   [`RenderFrameHostHandle::try_borrow_mut`]. This will return
///   a guard object which guarantees the existence of the `RenderFrameHost`
///   during its lifetime.
///
/// # Performance characteristics
///
/// The existence of this object registers an observer with the `WebContents`
/// and deregisters it on destruction. That is, of course, an overhead, but
/// that's necessary to keep track of liveness. (A more efficient
/// implementation would use a single observer for multiple such handles - but
/// this is a toy implementation).
///
/// In addition, each time you extract the value from this
/// `RenderFrameHostHandle`, a liveness check is performed. This involves
/// not just a null check but also some reference count manipulation.
/// If you're going to access the `RenderFrameHost` multiple times, it's
/// advised that you call [`RenderFrameHostHandle::try_borrow`] or
/// [`RenderFrameHostHandle::try_borrow_mut`] and then use
/// the result multiple times. The liveness check for the `RenderFrameHost`
/// will be performed only once at runtime.
///
/// # Destruction of RenderFrameHosts while borrowed
///
/// If you have called [`RenderFrameHostHandle::try_borrow`] (or its mutable
/// equivalent) and still have an outstanding borrow, any code path - via C++
/// - which results it the destruction of the `RenderFrameHost` will result in
/// a runtime panic.
pub struct RenderFrameHostHandle<'wc> {
    obs: Rc<RefCell<RenderFrameHostForWebContents>>,
    web_contents: Pin<&'wc mut ffi::content::WebContents>,
}

impl<'wc> RenderFrameHostHandle<'wc> {
    /// Create a memory-safe handle to a RenderFrameHost using its
    /// process ID and frame ID.
    pub fn from_id(
        render_process_id: c_int,
        render_frame_id: c_int,
        mut web_contents: Pin<&'wc mut ffi::content::WebContents>,
    ) -> Self {
        // Instantiate our WebContentsObserver subclass.
        let obs = RenderFrameHostForWebContents::new_rust_owned(RenderFrameHostForWebContents {
            rfh: ffi::content::RenderFrameHost::FromId(render_process_id, render_frame_id),
            cpp_peer: Default::default(),
        });

        // And now register it.
        // This nasty line will go away when autocxx is a bit more sophisticated.
        let superclass_ptr = cast_to_superclass(obs.as_ref().borrow_mut().peer_mut());

        // But this will remain unsafe. cxx policy is that any raw pointer
        // passed into a C++ function requires an unsafe {} block and that
        // is sensible. We may of course provide an ergonomic Rust wrapper
        // around WebContents which provides safe Rust equivalents
        // (using references or similar rather than pointers) in which case
        // this unsafe block would go away.
        unsafe { web_contents.as_mut().AddObserver(superclass_ptr) };

        Self { obs, web_contents }
    }

    /// Tries to return a mutable reference to the RenderFrameHost.
    /// Because this requires `self` to be `&mut`, and that lifetime is
    /// applied to the returned `RenderFrameHost`, the compiler will prevent
    /// multiple such references existing in Rust at the same time.
    /// This will return `None` if the RenderFrameHost were already destroyed.
    pub fn try_borrow_mut<'a>(
        &'a mut self,
    ) -> Option<impl PinMut<ffi::content::RenderFrameHost> + 'a> {
        let ref_mut = self.obs.as_ref().borrow_mut();
        if ref_mut.rfh.is_null() {
            None
        } else {
            Some(RenderFrameHostRefMut(ref_mut))
        }
    }

    /// Tries to return a reference to the RenderFrameHost.
    /// The compiler will prevent calls to this if anyone has an outstanding
    /// mutable reference from [`RenderFrameHostHandle::try_borrow_mut`].
    /// This will return `None` if the RenderFrameHost were already destroyed.
    #[allow(dead_code)]
    pub fn try_borrow<'a>(&'a self) -> Option<impl AsRef<ffi::content::RenderFrameHost> + 'a> {
        let ref_non_mut = self.obs.as_ref().borrow();
        if ref_non_mut.rfh.is_null() {
            None
        } else {
            Some(RenderFrameHostRef(ref_non_mut))
        }
    }
}

impl<'wc> Drop for RenderFrameHostHandle<'wc> {
    fn drop(&mut self) {
        // Unregister our observer.
        let superclass_ptr = cast_to_superclass(self.obs.as_ref().borrow_mut().peer_mut());
        unsafe { self.web_contents.as_mut().RemoveObserver(superclass_ptr) };
    }
}

impl<'wc> AsRef<ffi::content::RenderFrameHost> for RenderFrameHostHandle<'wc> {
    fn as_ref(&self) -> &ffi::content::RenderFrameHost {
        let ref_non_mut = self.obs.as_ref().borrow();
        // Safety: the .rfh field is guaranteed to be a RenderFrameHost
        // and we are observing its lifetime so it will be reset to null
        // if destroyed.
        unsafe { ref_non_mut.rfh.as_ref() }.expect("This RenderFrameHost was already destroyed")
    }
}

impl<'wc> PinMut<ffi::content::RenderFrameHost> for RenderFrameHostHandle<'wc> {
    fn pin_mut(&mut self) -> Pin<&mut ffi::content::RenderFrameHost> {
        let ref_mut = self.obs.as_ref().borrow_mut();
        // Safety: the .rfh field is guaranteed to be a RenderFrameHost
        // and we are observing its lifetime so it will be reset to null
        // if destroyed.
        unsafe { ref_mut.rfh.as_mut().map(|p| Pin::new_unchecked(p)) }
            .expect("This RenderFrameHost was already destroyed")
    }
}

impl<'wc> Deref for RenderFrameHostHandle<'wc> {
    type Target = ffi::content::RenderFrameHost;
    fn deref(&self) -> &Self::Target {
        self.as_ref()
    }
}

#[doc(hidden)]
struct RenderFrameHostRefMut<'a>(RefMut<'a, RenderFrameHostForWebContents>);

#[doc(hidden)]
struct RenderFrameHostRef<'a>(Ref<'a, RenderFrameHostForWebContents>);

impl<'a> AsRef<ffi::content::RenderFrameHost> for RenderFrameHostRef<'a> {
    fn as_ref(&self) -> &ffi::content::RenderFrameHost {
        // Safety:
        // Creation precondition is that self.0.rfh is not null
        // and it can't be destroyed whilst this borrow exists.
        unsafe { self.0.rfh.as_ref().unwrap() }
    }
}

impl<'a> PinMut<ffi::content::RenderFrameHost> for RenderFrameHostRefMut<'a> {
    fn pin_mut(&mut self) -> Pin<&mut ffi::content::RenderFrameHost> {
        // Safety:
        // Creation precondition is that self.0.rfh is not null
        // and it can't be destroyed whilst this borrow exists.
        unsafe { Pin::new_unchecked(self.0.rfh.as_mut().unwrap()) }
    }
}

impl<'a> AsRef<ffi::content::RenderFrameHost> for RenderFrameHostRefMut<'a> {
    fn as_ref(&self) -> &ffi::content::RenderFrameHost {
        // Safety:
        // Creation precondition is that self.0.rfh is not null
        // and it can't be destroyed whilst this borrow exists.
        unsafe { self.0.rfh.as_ref().unwrap() }
    }
}

impl<'a> Deref for RenderFrameHostRef<'a> {
    type Target = ffi::content::RenderFrameHost;
    fn deref(&self) -> &Self::Target {
        self.as_ref()
    }
}

impl<'a> Deref for RenderFrameHostRefMut<'a> {
    type Target = ffi::content::RenderFrameHost;
    fn deref(&self) -> &Self::Target {
        self.as_ref()
    }
}

#[is_subclass(superclass("content::WebContentsObserver"))]
#[doc(hidden)]
pub struct RenderFrameHostForWebContents {
    rfh: *mut ffi::content::RenderFrameHost,
}

impl ffi::content::WebContentsObserver_methods for RenderFrameHostForWebContents {
    unsafe fn RenderFrameDeleted(&mut self, destroyed_rfh: *mut ffi::content::RenderFrameHost) {
        if self.rfh == destroyed_rfh {
            self.rfh = std::ptr::null_mut()
        }
    }
}

fn cast_to_superclass(
    obs: Pin<&mut ffi::RenderFrameHostForWebContentsCpp>,
) -> *mut ffi::content::WebContentsObserver {
    // This horrid code will all go away once we implement
    // https://github.com/google/autocxx/issues/592; safe wrappers will
    // be automatically generated to allow upcasting to superclasses.
    // NB this code is probably actually _wrong_ too meanwhile; we need to cast
    // on the C++ side.
    let subclass_obs_ptr =
        unsafe { Pin::into_inner_unchecked(obs) } as *mut ffi::RenderFrameHostForWebContentsCpp;
    unsafe {
        std::mem::transmute::<
            *mut ffi::RenderFrameHostForWebContentsCpp,
            *mut ffi::content::WebContentsObserver,
        >(subclass_obs_ptr)
    }
}
<|endoftext|>


<commit_before>//! The CXX code generator for constructing and compiling C++ code.
//!
//! This is intended to be embedded into higher-level code generators.

#![allow(dead_code)]

mod gen;
mod syntax;

pub use crate::gen::{GeneratedCode, Opt};
use proc_macro2::TokenStream;
use std::error::Error as StdError;
use std::fmt::{self, Debug, Display};

pub struct Error(crate::gen::Error);

/// Generate C++ bindings code from a Rust token stream. This should be a Rust
/// token stream which somewhere contains a `#[cxx::bridge] mod {}`.
pub fn generate_header_and_cc(rust_source: TokenStream, opt: &Opt) -> Result<GeneratedCode, Error> {
    let syntax = syn::parse2(rust_source)
        .map_err(crate::gen::Error::from)
        .map_err(Error)?;
    gen::generate(syntax, opt).map_err(Error)
}

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Display::fmt(&self.0, f)
    }
}

impl Debug for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Debug::fmt(&self.0, f)
    }
}

impl StdError for Error {
    fn source(&self) -> Option<&(dyn StdError + 'static)> {
        self.0.source()
    }
}
<commit_msg>Link to some context about autocxx<commit_after>//! The CXX code generator for constructing and compiling C++ code.
//!
//! This is intended as a mechanism for embedding the `cxx` crate into
//! higher-level code generators. See [dtolnay/cxx#235] and
//! [https://github.com/google/autocxx].
//!
//! [dtolnay/cxx#235]: https://github.com/dtolnay/cxx/issues/235
//! [https://github.com/google/autocxx]: https://github.com/google/autocxx

#![allow(dead_code)]

mod gen;
mod syntax;

pub use crate::gen::{GeneratedCode, Opt};
use proc_macro2::TokenStream;
use std::error::Error as StdError;
use std::fmt::{self, Debug, Display};

pub struct Error(crate::gen::Error);

/// Generate C++ bindings code from a Rust token stream. This should be a Rust
/// token stream which somewhere contains a `#[cxx::bridge] mod {}`.
pub fn generate_header_and_cc(rust_source: TokenStream, opt: &Opt) -> Result<GeneratedCode, Error> {
    let syntax = syn::parse2(rust_source)
        .map_err(crate::gen::Error::from)
        .map_err(Error)?;
    gen::generate(syntax, opt).map_err(Error)
}

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Display::fmt(&self.0, f)
    }
}

impl Debug for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Debug::fmt(&self.0, f)
    }
}

impl StdError for Error {
    fn source(&self) -> Option<&(dyn StdError + 'static)> {
        self.0.source()
    }
}
<|endoftext|>


<commit_before>#![feature(no_std,lang_items,asm)]
#![feature(alloc,collections)]
#![feature(core_intrinsics,box_raw)]
#![feature(step_by,const_fn)]

#![no_std]

#![crate_type="staticlib"]
#![crate_name="rustcode"]

#[macro_use]
extern crate alloc_shim;
extern crate alloc;
extern crate collections;

use core::fmt;
use core::sync::atomic::Ordering;
use alloc::boxed::Box;
use alloc::arc::Arc;
use collections::String;

extern crate rlibc;

mod mutex;
mod lazy_global;

mod machine;
#[macro_use]
mod console;

mod vga;
mod mmu;
mod tasks;
mod acpi;
mod interrupts;
mod paging;
mod malloc;
mod ide;
mod smp;
mod user_mode;

use vga::Color::*;

pub use interrupts::{idt_desc};
pub use interrupts::handlers::{double_fault_handler, gpf_handler,
                               page_fault_handler, broadcast_timer_handler,
                               timer_handler, kbd_interrupt_handler,
                               write_handler, sleep_handler, exit_handler };
pub use malloc::{rust_allocate, rust_reallocate, rust_reallocate_inplace,
                 rust_deallocate, rust_usable_size, rust_stats_print };
pub use smp::{SMP_STACK_PTR, SMP_CR3};

#[lang="start"]
#[no_mangle]
pub fn k_main() {
    if smp::processor_count.fetch_add(1, Ordering::SeqCst) == 0 {
        paging::init();
        interrupts::init_idt();
        // YOU MAY NOW PAGE FAULT
        interrupts::init();
        smp::init(Arc::new(smp::Globals {
            processors: acpi::processor_list(),
            bsp: interrupts::apic::id(),
            the_code: ide::slurp_drive(1),
        }));
        tasks::init();

        let greet = "Hello from bare-bones Rust";
        console::puts("Hello");
        for i in 0..vga::ROWS {
            for j in 0..vga::COLS {
            vga::write_char_with_color(i, j, ' ', White, LightBlue);
            }
        }
        vga::paint_color(0, 0, 30, White, LightGreen);
        vga::write_string(10, 5, greet);
        vga::move_cursor(10, 5 + greet.len());
        vga::write_string_with_color(11, 10, "Test", Black, LightRed);

        let heap = Box::new('H');
        let heap2 = Box::new('!');
        vga::write_char(15,4,*heap);
        vga::write_char_with_color(15, 5, *heap2, LightGray, Pink);

        let mut string = String::from("Hello, ");
        string.push_str("paging");
        vga::write_string(3,5,&string);
        unsafe { *(0xB0_00_00_01 as *mut u32) = 0xcafecafe; }
        let processors = smp::processor_count.load(Ordering::SeqCst) as u8 + '0' as u8;
        vga::write_char(4, 4, processors as char);
        user_mode::init();
    }
    else { // Non-main processor
        interrupts::apic::enable_lapic();
        let id = interrupts::apic::id();
        let globals = smp::globals();
        let bsp_id = globals.bsp;
        log!("I am {}. The main processor is {}\r\n", id, bsp_id);
        if tasks::init() {
            user_mode::init();
        }
    }
}

#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
#[lang = "eh_personality"] extern fn eh_personality() {}

#[lang = "panic_fmt"]
pub extern fn rust_begin_unwind(args: fmt::Arguments,
                                file: &'static str, line: u32) -> ! {
    use core::fmt::Write;
    log!("\r\nPanic at {}:{}: ", file, line);
    let _ = console::Console.write_fmt(args);
    loop {};
}
<commit_msg>Remove unneeded feature flag<commit_after>#![feature(no_std,lang_items,asm)]
#![feature(alloc,collections)]
#![feature(core_intrinsics)]
#![feature(step_by,const_fn)]

#![no_std]

#![crate_type="staticlib"]
#![crate_name="rustcode"]

#[macro_use]
extern crate alloc_shim;
extern crate alloc;
extern crate collections;

use core::fmt;
use core::sync::atomic::Ordering;
use alloc::boxed::Box;
use alloc::arc::Arc;
use collections::String;

extern crate rlibc;

mod mutex;
mod lazy_global;

mod machine;
#[macro_use]
mod console;

mod vga;
mod mmu;
mod tasks;
mod acpi;
mod interrupts;
mod paging;
mod malloc;
mod ide;
mod smp;
mod user_mode;

use vga::Color::*;

pub use interrupts::{idt_desc};
pub use interrupts::handlers::{double_fault_handler, gpf_handler,
                               page_fault_handler, broadcast_timer_handler,
                               timer_handler, kbd_interrupt_handler,
                               write_handler, sleep_handler, exit_handler };
pub use malloc::{rust_allocate, rust_reallocate, rust_reallocate_inplace,
                 rust_deallocate, rust_usable_size, rust_stats_print };
pub use smp::{SMP_STACK_PTR, SMP_CR3};

#[lang="start"]
#[no_mangle]
pub fn k_main() {
    if smp::processor_count.fetch_add(1, Ordering::SeqCst) == 0 {
        paging::init();
        interrupts::init_idt();
        // YOU MAY NOW PAGE FAULT
        interrupts::init();
        smp::init(Arc::new(smp::Globals {
            processors: acpi::processor_list(),
            bsp: interrupts::apic::id(),
            the_code: ide::slurp_drive(1),
        }));
        tasks::init();

        let greet = "Hello from bare-bones Rust";
        console::puts("Hello");
        for i in 0..vga::ROWS {
            for j in 0..vga::COLS {
            vga::write_char_with_color(i, j, ' ', White, LightBlue);
            }
        }
        vga::paint_color(0, 0, 30, White, LightGreen);
        vga::write_string(10, 5, greet);
        vga::move_cursor(10, 5 + greet.len());
        vga::write_string_with_color(11, 10, "Test", Black, LightRed);

        let heap = Box::new('H');
        let heap2 = Box::new('!');
        vga::write_char(15,4,*heap);
        vga::write_char_with_color(15, 5, *heap2, LightGray, Pink);

        let mut string = String::from("Hello, ");
        string.push_str("paging");
        vga::write_string(3,5,&string);
        unsafe { *(0xB0_00_00_01 as *mut u32) = 0xcafecafe; }
        let processors = smp::processor_count.load(Ordering::SeqCst) as u8 + '0' as u8;
        vga::write_char(4, 4, processors as char);
        user_mode::init();
    }
    else { // Non-main processor
        interrupts::apic::enable_lapic();
        let id = interrupts::apic::id();
        let globals = smp::globals();
        let bsp_id = globals.bsp;
        log!("I am {}. The main processor is {}\r\n", id, bsp_id);
        if tasks::init() {
            user_mode::init();
        }
    }
}

#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
#[lang = "eh_personality"] extern fn eh_personality() {}

#[lang = "panic_fmt"]
pub extern fn rust_begin_unwind(args: fmt::Arguments,
                                file: &'static str, line: u32) -> ! {
    use core::fmt::Write;
    log!("\r\nPanic at {}:{}: ", file, line);
    let _ = console::Console.write_fmt(args);
    loop {};
}
<|endoftext|>


<commit_before>extern crate chrono;
extern crate tina;

use chrono::*;
use tina::*;

mod eew_builder;
use eew_builder::*;

struct MiniEEW {
	issue_pattern: IssuePattern,
	kind: Kind,
	status: Status,
	detail: Option<MiniEEWDetail>,
}

struct MiniEEWDetail {
	depth: Option<f32>,
	magnitude: Option<f32>,
	maximum_intensity: Option<IntensityClass>,
	warning_status: WarningStatus,
}

impl From<MiniEEW> for EEW {

	fn from(v: MiniEEW) -> EEW
	{
		EEW {
			issue_pattern: v.issue_pattern, source: Source::Tokyo, kind: v.kind,
			issued_at: UTC.ymd(2010, 1, 1).and_hms(1, 0, 2),
			occurred_at: UTC.ymd(2010, 1, 1).and_hms(0, 55, 59),
			id: "ND20100101005559".to_owned(), status: v.status, number: 10,
			detail: v.detail.map(|d| d.into()),
		}
	}
}

impl From<MiniEEWDetail> for EEWDetail {

	fn from(v: MiniEEWDetail) -> EEWDetail
	{
		EEWDetail {
			epicenter_name: "奈良県".to_owned(), epicenter: (34.4, 135.7),
			depth: v.depth, magnitude: v.magnitude,
			maximum_intensity: v.maximum_intensity,
			epicenter_accuracy: EpicenterAccuracy::GridSearchLow,
			depth_accuracy: DepthAccuracy::GridSearchLow,
			magnitude_accuracy: MagnitudeAccuracy::SWave,
			epicenter_category: EpicenterCategory::Land,
			warning_status: v.warning_status,
			intensity_change: IntensityChange::Unknown,
			change_reason: ChangeReason::Unknown,
			area_info: vec!{},
		}
	}
}

#[test]
fn it_should_format_cancel_eew()
{
	let eew = EEWBuilder::new()
		.issue_pattern(IssuePattern::Cancel)
		.kind(Kind::Cancel)
		.detail_none()
		.build();

	let expected = "[取消] --- | 第10報 NDXXXX".to_owned();

	let result = ja_format_eew_short(&eew, None);

	assert_eq!(result, Some(expected));
}

#[test]
fn it_should_format_intensity_only_eew()
{
	let eew = EEWBuilder::new()
		.issue_pattern(IssuePattern::IntensityOnly)
		.magnitude(None)
		.build();

	let expected =
		"[速報] 奈良県 震度5弱 M--- 10km (N34.4/E135.7) 09:55:59発生 | 第10報 NDXXXX".to_owned();

	let result = ja_format_eew_short(&eew, None);

	assert_eq!(result, Some(expected));
}

#[test]
fn it_should_format_low_accuracy_eew()
{
	let eew = EEWBuilder::new()
		.issue_pattern(IssuePattern::LowAccuracy)
		.build();

	let expected =
		"[予報] 奈良県 震度5弱 M5.9 10km (N34.4/E135.7) 09:55:59発生 | 第10報 NDXXXX".to_owned();

	let result = ja_format_eew_short(&eew, None);

	assert_eq!(result, Some(expected));
}

#[test]
fn it_should_format_high_accuracy_eew()
{
	let eew = EEWBuilder::new()
		.build();

	let expected =
		"[予報] 奈良県 震度5弱 M5.9 10km (N34.4/E135.7) 09:55:59発生 | 第10報 NDXXXX".to_owned();

	let result = ja_format_eew_short(&eew, None);

	assert_eq!(result, Some(expected));
}

#[test]
fn it_should_format_alert_eew_with_intensity_only()
{
	let eew = EEWBuilder::new()
		.issue_pattern(IssuePattern::IntensityOnly)
		.magnitude(None)
		.warning_status(WarningStatus::Alert)
		.build();

	let expected =
		"[警報] 奈良県 震度5弱 M--- 10km (N34.4/E135.7) 09:55:59発生 | 第10報 NDXXXX".to_owned();

	let result = ja_format_eew_short(&eew, None);

	assert_eq!(result, Some(expected));
}

#[test]
fn it_should_format_alert_eew_with_low_accuracy()
{
	let eew = EEWBuilder::new()
		.issue_pattern(IssuePattern::LowAccuracy)
		.warning_status(WarningStatus::Alert)
		.build();

	let expected =
		"[警報] 奈良県 震度5弱 M5.9 10km (N34.4/E135.7) 09:55:59発生 | 第10報 NDXXXX".to_owned();

	let result = ja_format_eew_short(&eew, None);

	assert_eq!(result, Some(expected));
}

#[test]
fn it_should_format_alert_eew_with_high_accuracy()
{
	let eew = EEWBuilder::new()
		.issue_pattern(IssuePattern::HighAccuracy)
		.warning_status(WarningStatus::Alert)
		.build();

	let expected =
		"[警報] 奈良県 震度5弱 M5.9 10km (N34.4/E135.7) 09:55:59発生 | 第10報 NDXXXX".to_owned();

	let result = ja_format_eew_short(&eew, None);

	assert_eq!(result, Some(expected));
}

#[test]
fn it_should_format_last_eew()
{
	let eew = EEWBuilder::new()
		.status(Status::Last)
		.warning_status(WarningStatus::Alert)
		.build();

	let expected =
		"[警報/最終] 奈良県 震度5弱 M5.9 10km (N34.4/E135.7) 09:55:59発生 | 第10報 NDXXXX".to_owned();

	let result = ja_format_eew_short(&eew, None);

	assert_eq!(result, Some(expected));
}

#[test]
fn it_should_format_last_with_correction_eew()
{
	let eew = EEWBuilder::new()
		.status(Status::LastWithCorrection)
		.warning_status(WarningStatus::Alert)
		.build();

	let expected =
		"[警報/最終] 奈良県 震度5弱 M5.9 10km (N34.4/E135.7) 09:55:59発生 | 第10報 NDXXXX".to_owned();

	let result = ja_format_eew_short(&eew, None);

	assert_eq!(result, Some(expected));
}

#[test]
fn it_should_format_correction_eew()
{
	let eew = EEWBuilder::new()
		.status(Status::Correction)
		.warning_status(WarningStatus::Alert)
		.build();

	let expected =
		"[警報] 奈良県 震度5弱 M5.9 10km (N34.4/E135.7) 09:55:59発生 | 第10報 NDXXXX".to_owned();

	let result = ja_format_eew_short(&eew, None);

	assert_eq!(result, Some(expected));
}

#[test]
fn it_should_format_eew_with_unknown_values()
{
	let eew = EEWBuilder::new()
		.depth(None)
		.magnitude(None)
		.maximum_intensity(None)
		.build();

	let expected =
		"[予報] 奈良県 震度不明 M--- ---km (N34.4/E135.7) 09:55:59発生 | 第10報 NDXXXX".to_owned();

	let result = ja_format_eew_short(&eew, None);

	assert_eq!(result, Some(expected));
}
<commit_msg>Remove unused code<commit_after>extern crate chrono;
extern crate tina;

use tina::*;

mod eew_builder;
use eew_builder::*;

#[test]
fn it_should_format_cancel_eew()
{
	let eew = EEWBuilder::new()
		.issue_pattern(IssuePattern::Cancel)
		.kind(Kind::Cancel)
		.detail_none()
		.build();

	let expected = "[取消] --- | 第10報 NDXXXX".to_owned();

	let result = ja_format_eew_short(&eew, None);

	assert_eq!(result, Some(expected));
}

#[test]
fn it_should_format_intensity_only_eew()
{
	let eew = EEWBuilder::new()
		.issue_pattern(IssuePattern::IntensityOnly)
		.magnitude(None)
		.build();

	let expected =
		"[速報] 奈良県 震度5弱 M--- 10km (N34.4/E135.7) 09:55:59発生 | 第10報 NDXXXX".to_owned();

	let result = ja_format_eew_short(&eew, None);

	assert_eq!(result, Some(expected));
}

#[test]
fn it_should_format_low_accuracy_eew()
{
	let eew = EEWBuilder::new()
		.issue_pattern(IssuePattern::LowAccuracy)
		.build();

	let expected =
		"[予報] 奈良県 震度5弱 M5.9 10km (N34.4/E135.7) 09:55:59発生 | 第10報 NDXXXX".to_owned();

	let result = ja_format_eew_short(&eew, None);

	assert_eq!(result, Some(expected));
}

#[test]
fn it_should_format_high_accuracy_eew()
{
	let eew = EEWBuilder::new()
		.build();

	let expected =
		"[予報] 奈良県 震度5弱 M5.9 10km (N34.4/E135.7) 09:55:59発生 | 第10報 NDXXXX".to_owned();

	let result = ja_format_eew_short(&eew, None);

	assert_eq!(result, Some(expected));
}

#[test]
fn it_should_format_alert_eew_with_intensity_only()
{
	let eew = EEWBuilder::new()
		.issue_pattern(IssuePattern::IntensityOnly)
		.magnitude(None)
		.warning_status(WarningStatus::Alert)
		.build();

	let expected =
		"[警報] 奈良県 震度5弱 M--- 10km (N34.4/E135.7) 09:55:59発生 | 第10報 NDXXXX".to_owned();

	let result = ja_format_eew_short(&eew, None);

	assert_eq!(result, Some(expected));
}

#[test]
fn it_should_format_alert_eew_with_low_accuracy()
{
	let eew = EEWBuilder::new()
		.issue_pattern(IssuePattern::LowAccuracy)
		.warning_status(WarningStatus::Alert)
		.build();

	let expected =
		"[警報] 奈良県 震度5弱 M5.9 10km (N34.4/E135.7) 09:55:59発生 | 第10報 NDXXXX".to_owned();

	let result = ja_format_eew_short(&eew, None);

	assert_eq!(result, Some(expected));
}

#[test]
fn it_should_format_alert_eew_with_high_accuracy()
{
	let eew = EEWBuilder::new()
		.issue_pattern(IssuePattern::HighAccuracy)
		.warning_status(WarningStatus::Alert)
		.build();

	let expected =
		"[警報] 奈良県 震度5弱 M5.9 10km (N34.4/E135.7) 09:55:59発生 | 第10報 NDXXXX".to_owned();

	let result = ja_format_eew_short(&eew, None);

	assert_eq!(result, Some(expected));
}

#[test]
fn it_should_format_last_eew()
{
	let eew = EEWBuilder::new()
		.status(Status::Last)
		.warning_status(WarningStatus::Alert)
		.build();

	let expected =
		"[警報/最終] 奈良県 震度5弱 M5.9 10km (N34.4/E135.7) 09:55:59発生 | 第10報 NDXXXX".to_owned();

	let result = ja_format_eew_short(&eew, None);

	assert_eq!(result, Some(expected));
}

#[test]
fn it_should_format_last_with_correction_eew()
{
	let eew = EEWBuilder::new()
		.status(Status::LastWithCorrection)
		.warning_status(WarningStatus::Alert)
		.build();

	let expected =
		"[警報/最終] 奈良県 震度5弱 M5.9 10km (N34.4/E135.7) 09:55:59発生 | 第10報 NDXXXX".to_owned();

	let result = ja_format_eew_short(&eew, None);

	assert_eq!(result, Some(expected));
}

#[test]
fn it_should_format_correction_eew()
{
	let eew = EEWBuilder::new()
		.status(Status::Correction)
		.warning_status(WarningStatus::Alert)
		.build();

	let expected =
		"[警報] 奈良県 震度5弱 M5.9 10km (N34.4/E135.7) 09:55:59発生 | 第10報 NDXXXX".to_owned();

	let result = ja_format_eew_short(&eew, None);

	assert_eq!(result, Some(expected));
}

#[test]
fn it_should_format_eew_with_unknown_values()
{
	let eew = EEWBuilder::new()
		.depth(None)
		.magnitude(None)
		.maximum_intensity(None)
		.build();

	let expected =
		"[予報] 奈良県 震度不明 M--- ---km (N34.4/E135.7) 09:55:59発生 | 第10報 NDXXXX".to_owned();

	let result = ja_format_eew_short(&eew, None);

	assert_eq!(result, Some(expected));
}
<|endoftext|>


<commit_before>use crate::utils::{get_item_name, in_macro, snippet_with_applicability, span_lint, span_lint_and_sugg, walk_ptrs_ty};
use rustc::hir::def_id::DefId;
use rustc::hir::*;
use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use rustc::ty;
use rustc::{declare_tool_lint, lint_array};
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
use syntax::ast::{Lit, LitKind, Name};
use syntax::source_map::{Span, Spanned};

/// **What it does:** Checks for getting the length of something via `.len()`
/// just to compare to zero, and suggests using `.is_empty()` where applicable.
///
/// **Why is this bad?** Some structures can answer `.is_empty()` much faster
/// than calculating their length. Notably, for slices, getting the length
/// requires a subtraction whereas `.is_empty()` is just a comparison. So it is
/// good to get into the habit of using `.is_empty()`, and having it is cheap.
/// Besides, it makes the intent clearer than a manual comparison.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// if x.len() == 0 {
///     ..
/// }
/// if y.len() != 0 {
///     ..
/// }
/// ```
/// instead use
/// ```rust
/// if x.len().is_empty() {
///     ..
/// }
/// if !y.len().is_empty() {
///     ..
/// }
/// ```
declare_clippy_lint! {
pub LEN_ZERO,
style,
"checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` \
 could be used instead"
}

/// **What it does:** Checks for items that implement `.len()` but not
/// `.is_empty()`.
///
/// **Why is this bad?** It is good custom to have both methods, because for
/// some data structures, asking about the length will be a costly operation,
/// whereas `.is_empty()` can usually answer in constant time. Also it used to
/// lead to false positives on the [`len_zero`](#len_zero) lint – currently that
/// lint will ignore such entities.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// impl X {
///     pub fn len(&self) -> usize {
///         ..
///     }
/// }
/// ```
declare_clippy_lint! {
    pub LEN_WITHOUT_IS_EMPTY,
    style,
    "traits or impls with a public `len` method but no corresponding `is_empty` method"
}

#[derive(Copy, Clone)]
pub struct LenZero;

impl LintPass for LenZero {
    fn get_lints(&self) -> LintArray {
        lint_array!(LEN_ZERO, LEN_WITHOUT_IS_EMPTY)
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LenZero {
    fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
        if in_macro(item.span) {
            return;
        }

        match item.node {
            ItemKind::Trait(_, _, _, _, ref trait_items) => check_trait_items(cx, item, trait_items),
            ItemKind::Impl(_, _, _, _, None, _, ref impl_items) => check_impl_items(cx, item, impl_items),
            _ => (),
        }
    }

    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
        if in_macro(expr.span) {
            return;
        }

        if let ExprKind::Binary(Spanned { node: cmp, .. }, ref left, ref right) = expr.node {
            match cmp {
                BinOpKind::Eq => {
                    check_cmp(cx, expr.span, left, right, "", 0); // len == 0
                    check_cmp(cx, expr.span, right, left, "", 0); // 0 == len
                },
                BinOpKind::Ne => {
                    check_cmp(cx, expr.span, left, right, "!", 0); // len != 0
                    check_cmp(cx, expr.span, right, left, "!", 0); // 0 != len
                },
                BinOpKind::Gt => {
                    check_cmp(cx, expr.span, left, right, "!", 0); // len > 0
                    check_cmp(cx, expr.span, right, left, "", 1); // 1 > len
                },
                BinOpKind::Lt => {
                    check_cmp(cx, expr.span, left, right, "", 1); // len < 1
                    check_cmp(cx, expr.span, right, left, "!", 0); // 0 < len
                },
                BinOpKind::Ge => check_cmp(cx, expr.span, left, right, "!", 1), // len <= 1
                BinOpKind::Le => check_cmp(cx, expr.span, right, left, "!", 1), // 1 >= len
                _ => (),
            }
        }
    }
}

fn check_trait_items(cx: &LateContext<'_, '_>, visited_trait: &Item, trait_items: &[TraitItemRef]) {
    fn is_named_self(cx: &LateContext<'_, '_>, item: &TraitItemRef, name: &str) -> bool {
        item.ident.name == name
            && if let AssociatedItemKind::Method { has_self } = item.kind {
                has_self && {
                    let did = cx.tcx.hir().local_def_id(item.id.node_id);
                    cx.tcx.fn_sig(did).inputs().skip_binder().len() == 1
                }
            } else {
                false
            }
    }

    // fill the set with current and super traits
    fn fill_trait_set(traitt: DefId, set: &mut FxHashSet<DefId>, cx: &LateContext<'_, '_>) {
        if set.insert(traitt) {
            for supertrait in rustc::traits::supertrait_def_ids(cx.tcx, traitt) {
                fill_trait_set(supertrait, set, cx);
            }
        }
    }

    if cx.access_levels.is_exported(visited_trait.id) && trait_items.iter().any(|i| is_named_self(cx, i, "len")) {
        let mut current_and_super_traits = FxHashSet::default();
        let visited_trait_def_id = cx.tcx.hir().local_def_id(visited_trait.id);
        fill_trait_set(visited_trait_def_id, &mut current_and_super_traits, cx);

        let is_empty_method_found = current_and_super_traits
            .iter()
            .flat_map(|&i| cx.tcx.associated_items(i))
            .any(|i| {
                i.kind == ty::AssociatedKind::Method
                    && i.method_has_self_argument
                    && i.ident.name == "is_empty"
                    && cx.tcx.fn_sig(i.def_id).inputs().skip_binder().len() == 1
            });

        if !is_empty_method_found {
            span_lint(
                cx,
                LEN_WITHOUT_IS_EMPTY,
                visited_trait.span,
                &format!(
                    "trait `{}` has a `len` method but no (possibly inherited) `is_empty` method",
                    visited_trait.ident.name
                ),
            );
        }
    }
}

fn check_impl_items(cx: &LateContext<'_, '_>, item: &Item, impl_items: &[ImplItemRef]) {
    fn is_named_self(cx: &LateContext<'_, '_>, item: &ImplItemRef, name: &str) -> bool {
        item.ident.name == name
            && if let AssociatedItemKind::Method { has_self } = item.kind {
                has_self && {
                    let did = cx.tcx.hir().local_def_id(item.id.node_id);
                    cx.tcx.fn_sig(did).inputs().skip_binder().len() == 1
                }
            } else {
                false
            }
    }

    let is_empty = if let Some(is_empty) = impl_items.iter().find(|i| is_named_self(cx, i, "is_empty")) {
        if cx.access_levels.is_exported(is_empty.id.node_id) {
            return;
        } else {
            "a private"
        }
    } else {
        "no corresponding"
    };

    if let Some(i) = impl_items.iter().find(|i| is_named_self(cx, i, "len")) {
        if cx.access_levels.is_exported(i.id.node_id) {
            let def_id = cx.tcx.hir().local_def_id(item.id);
            let ty = cx.tcx.type_of(def_id);

            span_lint(
                cx,
                LEN_WITHOUT_IS_EMPTY,
                item.span,
                &format!(
                    "item `{}` has a public `len` method but {} `is_empty` method",
                    ty, is_empty
                ),
            );
        }
    }
}

fn check_cmp(cx: &LateContext<'_, '_>, span: Span, method: &Expr, lit: &Expr, op: &str, compare_to: u32) {
    if let (&ExprKind::MethodCall(ref method_path, _, ref args), &ExprKind::Lit(ref lit)) = (&method.node, &lit.node) {
        // check if we are in an is_empty() method
        if let Some(name) = get_item_name(cx, method) {
            if name == "is_empty" {
                return;
            }
        }

        check_len(cx, span, method_path.ident.name, args, lit, op, compare_to)
    }
}

fn check_len(
    cx: &LateContext<'_, '_>,
    span: Span,
    method_name: Name,
    args: &[Expr],
    lit: &Lit,
    op: &str,
    compare_to: u32,
) {
    if let Spanned {
        node: LitKind::Int(lit, _),
        ..
    } = *lit
    {
        // check if length is compared to the specified number
        if lit != u128::from(compare_to) {
            return;
        }

        if method_name == "len" && args.len() == 1 && has_is_empty(cx, &args[0]) {
            let mut applicability = Applicability::MachineApplicable;
            span_lint_and_sugg(
                cx,
                LEN_ZERO,
                span,
                &format!("length comparison to {}", if compare_to == 0 { "zero" } else { "one" }),
                "using `is_empty` is clearer and more explicit",
                format!(
                    "{}{}.is_empty()",
                    op,
                    snippet_with_applicability(cx, args[0].span, "_", &mut applicability)
                ),
                applicability,
            );
        }
    }
}

/// Check if this type has an `is_empty` method.
fn has_is_empty(cx: &LateContext<'_, '_>, expr: &Expr) -> bool {
    /// Get an `AssociatedItem` and return true if it matches `is_empty(self)`.
    fn is_is_empty(cx: &LateContext<'_, '_>, item: &ty::AssociatedItem) -> bool {
        if let ty::AssociatedKind::Method = item.kind {
            if item.ident.name == "is_empty" {
                let sig = cx.tcx.fn_sig(item.def_id);
                let ty = sig.skip_binder();
                ty.inputs().len() == 1
            } else {
                false
            }
        } else {
            false
        }
    }

    /// Check the inherent impl's items for an `is_empty(self)` method.
    fn has_is_empty_impl(cx: &LateContext<'_, '_>, id: DefId) -> bool {
        cx.tcx
            .inherent_impls(id)
            .iter()
            .any(|imp| cx.tcx.associated_items(*imp).any(|item| is_is_empty(cx, &item)))
    }

    let ty = &walk_ptrs_ty(cx.tables.expr_ty(expr));
    match ty.sty {
        ty::Dynamic(ref tt, ..) => {
            if let Some(principal) = tt.principal() {
                cx.tcx
                    .associated_items(principal.def_id())
                    .any(|item| is_is_empty(cx, &item))
            } else {
                false
            }
        },
        ty::Projection(ref proj) => has_is_empty_impl(cx, proj.item_def_id),
        ty::Adt(id, _) => has_is_empty_impl(cx, id.did),
        ty::Array(..) | ty::Slice(..) | ty::Str => true,
        _ => false,
    }
}
<commit_msg>Auto merge of #3653 - gendx:master, r=phansch<commit_after>use crate::utils::{get_item_name, in_macro, snippet_with_applicability, span_lint, span_lint_and_sugg, walk_ptrs_ty};
use rustc::hir::def_id::DefId;
use rustc::hir::*;
use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use rustc::ty;
use rustc::{declare_tool_lint, lint_array};
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
use syntax::ast::{Lit, LitKind, Name};
use syntax::source_map::{Span, Spanned};

/// **What it does:** Checks for getting the length of something via `.len()`
/// just to compare to zero, and suggests using `.is_empty()` where applicable.
///
/// **Why is this bad?** Some structures can answer `.is_empty()` much faster
/// than calculating their length. Notably, for slices, getting the length
/// requires a subtraction whereas `.is_empty()` is just a comparison. So it is
/// good to get into the habit of using `.is_empty()`, and having it is cheap.
/// Besides, it makes the intent clearer than a manual comparison.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// if x.len() == 0 {
///     ..
/// }
/// if y.len() != 0 {
///     ..
/// }
/// ```
/// instead use
/// ```rust
/// if x.is_empty() {
///     ..
/// }
/// if !y.is_empty() {
///     ..
/// }
/// ```
declare_clippy_lint! {
pub LEN_ZERO,
style,
"checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` \
 could be used instead"
}

/// **What it does:** Checks for items that implement `.len()` but not
/// `.is_empty()`.
///
/// **Why is this bad?** It is good custom to have both methods, because for
/// some data structures, asking about the length will be a costly operation,
/// whereas `.is_empty()` can usually answer in constant time. Also it used to
/// lead to false positives on the [`len_zero`](#len_zero) lint – currently that
/// lint will ignore such entities.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// impl X {
///     pub fn len(&self) -> usize {
///         ..
///     }
/// }
/// ```
declare_clippy_lint! {
    pub LEN_WITHOUT_IS_EMPTY,
    style,
    "traits or impls with a public `len` method but no corresponding `is_empty` method"
}

#[derive(Copy, Clone)]
pub struct LenZero;

impl LintPass for LenZero {
    fn get_lints(&self) -> LintArray {
        lint_array!(LEN_ZERO, LEN_WITHOUT_IS_EMPTY)
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LenZero {
    fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
        if in_macro(item.span) {
            return;
        }

        match item.node {
            ItemKind::Trait(_, _, _, _, ref trait_items) => check_trait_items(cx, item, trait_items),
            ItemKind::Impl(_, _, _, _, None, _, ref impl_items) => check_impl_items(cx, item, impl_items),
            _ => (),
        }
    }

    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
        if in_macro(expr.span) {
            return;
        }

        if let ExprKind::Binary(Spanned { node: cmp, .. }, ref left, ref right) = expr.node {
            match cmp {
                BinOpKind::Eq => {
                    check_cmp(cx, expr.span, left, right, "", 0); // len == 0
                    check_cmp(cx, expr.span, right, left, "", 0); // 0 == len
                },
                BinOpKind::Ne => {
                    check_cmp(cx, expr.span, left, right, "!", 0); // len != 0
                    check_cmp(cx, expr.span, right, left, "!", 0); // 0 != len
                },
                BinOpKind::Gt => {
                    check_cmp(cx, expr.span, left, right, "!", 0); // len > 0
                    check_cmp(cx, expr.span, right, left, "", 1); // 1 > len
                },
                BinOpKind::Lt => {
                    check_cmp(cx, expr.span, left, right, "", 1); // len < 1
                    check_cmp(cx, expr.span, right, left, "!", 0); // 0 < len
                },
                BinOpKind::Ge => check_cmp(cx, expr.span, left, right, "!", 1), // len >= 1
                BinOpKind::Le => check_cmp(cx, expr.span, right, left, "!", 1), // 1 <= len
                _ => (),
            }
        }
    }
}

fn check_trait_items(cx: &LateContext<'_, '_>, visited_trait: &Item, trait_items: &[TraitItemRef]) {
    fn is_named_self(cx: &LateContext<'_, '_>, item: &TraitItemRef, name: &str) -> bool {
        item.ident.name == name
            && if let AssociatedItemKind::Method { has_self } = item.kind {
                has_self && {
                    let did = cx.tcx.hir().local_def_id(item.id.node_id);
                    cx.tcx.fn_sig(did).inputs().skip_binder().len() == 1
                }
            } else {
                false
            }
    }

    // fill the set with current and super traits
    fn fill_trait_set(traitt: DefId, set: &mut FxHashSet<DefId>, cx: &LateContext<'_, '_>) {
        if set.insert(traitt) {
            for supertrait in rustc::traits::supertrait_def_ids(cx.tcx, traitt) {
                fill_trait_set(supertrait, set, cx);
            }
        }
    }

    if cx.access_levels.is_exported(visited_trait.id) && trait_items.iter().any(|i| is_named_self(cx, i, "len")) {
        let mut current_and_super_traits = FxHashSet::default();
        let visited_trait_def_id = cx.tcx.hir().local_def_id(visited_trait.id);
        fill_trait_set(visited_trait_def_id, &mut current_and_super_traits, cx);

        let is_empty_method_found = current_and_super_traits
            .iter()
            .flat_map(|&i| cx.tcx.associated_items(i))
            .any(|i| {
                i.kind == ty::AssociatedKind::Method
                    && i.method_has_self_argument
                    && i.ident.name == "is_empty"
                    && cx.tcx.fn_sig(i.def_id).inputs().skip_binder().len() == 1
            });

        if !is_empty_method_found {
            span_lint(
                cx,
                LEN_WITHOUT_IS_EMPTY,
                visited_trait.span,
                &format!(
                    "trait `{}` has a `len` method but no (possibly inherited) `is_empty` method",
                    visited_trait.ident.name
                ),
            );
        }
    }
}

fn check_impl_items(cx: &LateContext<'_, '_>, item: &Item, impl_items: &[ImplItemRef]) {
    fn is_named_self(cx: &LateContext<'_, '_>, item: &ImplItemRef, name: &str) -> bool {
        item.ident.name == name
            && if let AssociatedItemKind::Method { has_self } = item.kind {
                has_self && {
                    let did = cx.tcx.hir().local_def_id(item.id.node_id);
                    cx.tcx.fn_sig(did).inputs().skip_binder().len() == 1
                }
            } else {
                false
            }
    }

    let is_empty = if let Some(is_empty) = impl_items.iter().find(|i| is_named_self(cx, i, "is_empty")) {
        if cx.access_levels.is_exported(is_empty.id.node_id) {
            return;
        } else {
            "a private"
        }
    } else {
        "no corresponding"
    };

    if let Some(i) = impl_items.iter().find(|i| is_named_self(cx, i, "len")) {
        if cx.access_levels.is_exported(i.id.node_id) {
            let def_id = cx.tcx.hir().local_def_id(item.id);
            let ty = cx.tcx.type_of(def_id);

            span_lint(
                cx,
                LEN_WITHOUT_IS_EMPTY,
                item.span,
                &format!(
                    "item `{}` has a public `len` method but {} `is_empty` method",
                    ty, is_empty
                ),
            );
        }
    }
}

fn check_cmp(cx: &LateContext<'_, '_>, span: Span, method: &Expr, lit: &Expr, op: &str, compare_to: u32) {
    if let (&ExprKind::MethodCall(ref method_path, _, ref args), &ExprKind::Lit(ref lit)) = (&method.node, &lit.node) {
        // check if we are in an is_empty() method
        if let Some(name) = get_item_name(cx, method) {
            if name == "is_empty" {
                return;
            }
        }

        check_len(cx, span, method_path.ident.name, args, lit, op, compare_to)
    }
}

fn check_len(
    cx: &LateContext<'_, '_>,
    span: Span,
    method_name: Name,
    args: &[Expr],
    lit: &Lit,
    op: &str,
    compare_to: u32,
) {
    if let Spanned {
        node: LitKind::Int(lit, _),
        ..
    } = *lit
    {
        // check if length is compared to the specified number
        if lit != u128::from(compare_to) {
            return;
        }

        if method_name == "len" && args.len() == 1 && has_is_empty(cx, &args[0]) {
            let mut applicability = Applicability::MachineApplicable;
            span_lint_and_sugg(
                cx,
                LEN_ZERO,
                span,
                &format!("length comparison to {}", if compare_to == 0 { "zero" } else { "one" }),
                "using `is_empty` is clearer and more explicit",
                format!(
                    "{}{}.is_empty()",
                    op,
                    snippet_with_applicability(cx, args[0].span, "_", &mut applicability)
                ),
                applicability,
            );
        }
    }
}

/// Check if this type has an `is_empty` method.
fn has_is_empty(cx: &LateContext<'_, '_>, expr: &Expr) -> bool {
    /// Get an `AssociatedItem` and return true if it matches `is_empty(self)`.
    fn is_is_empty(cx: &LateContext<'_, '_>, item: &ty::AssociatedItem) -> bool {
        if let ty::AssociatedKind::Method = item.kind {
            if item.ident.name == "is_empty" {
                let sig = cx.tcx.fn_sig(item.def_id);
                let ty = sig.skip_binder();
                ty.inputs().len() == 1
            } else {
                false
            }
        } else {
            false
        }
    }

    /// Check the inherent impl's items for an `is_empty(self)` method.
    fn has_is_empty_impl(cx: &LateContext<'_, '_>, id: DefId) -> bool {
        cx.tcx
            .inherent_impls(id)
            .iter()
            .any(|imp| cx.tcx.associated_items(*imp).any(|item| is_is_empty(cx, &item)))
    }

    let ty = &walk_ptrs_ty(cx.tables.expr_ty(expr));
    match ty.sty {
        ty::Dynamic(ref tt, ..) => {
            if let Some(principal) = tt.principal() {
                cx.tcx
                    .associated_items(principal.def_id())
                    .any(|item| is_is_empty(cx, &item))
            } else {
                false
            }
        },
        ty::Projection(ref proj) => has_is_empty_impl(cx, proj.item_def_id),
        ty::Adt(id, _) => has_is_empty_impl(cx, id.did),
        ty::Array(..) | ty::Slice(..) | ty::Str => true,
        _ => false,
    }
}
<|endoftext|>


<commit_before>use crate::utils::span_lint_and_sugg;
use if_chain::if_chain;
use rustc::hir::def::{CtorKind, Def};
use rustc::hir::intravisit::{walk_item, walk_path, walk_ty, NestedVisitorMap, Visitor};
use rustc::hir::*;
use rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
use rustc::ty;
use rustc::{declare_tool_lint, lint_array};
use rustc_errors::Applicability;
use syntax_pos::symbol::keywords::SelfUpper;

/// **What it does:** Checks for unnecessary repetition of structure name when a
/// replacement with `Self` is applicable.
///
/// **Why is this bad?** Unnecessary repetition. Mixed use of `Self` and struct
/// name
/// feels inconsistent.
///
/// **Known problems:**
/// - False positive when using associated types (#2843)
/// - False positives in some situations when using generics (#3410)
///
/// **Example:**
/// ```rust
/// struct Foo {}
/// impl Foo {
///     fn new() -> Foo {
///         Foo {}
///     }
/// }
/// ```
/// could be
/// ```rust
/// struct Foo {}
/// impl Foo {
///     fn new() -> Self {
///         Self {}
///     }
/// }
/// ```
declare_clippy_lint! {
    pub USE_SELF,
    pedantic,
    "Unnecessary structure name repetition whereas `Self` is applicable"
}

#[derive(Copy, Clone, Default)]
pub struct UseSelf;

impl LintPass for UseSelf {
    fn get_lints(&self) -> LintArray {
        lint_array!(USE_SELF)
    }
}

const SEGMENTS_MSG: &str = "segments should be composed of at least 1 element";

fn span_use_self_lint(cx: &LateContext<'_, '_>, path: &Path) {
    // path segments only include actual path, no methods or fields
    let last_path_span = path.segments.last().expect(SEGMENTS_MSG).ident.span;
    // `to()` doesn't shorten span, so we shorten it with `until(..)`
    // and then include it with `to(..)`
    let span = path.span.until(last_path_span).to(last_path_span);

    span_lint_and_sugg(
        cx,
        USE_SELF,
        span,
        "unnecessary structure name repetition",
        "use the applicable keyword",
        "Self".to_owned(),
        Applicability::MachineApplicable,
    );
}

struct TraitImplTyVisitor<'a, 'tcx: 'a> {
    item_type: ty::Ty<'tcx>,
    cx: &'a LateContext<'a, 'tcx>,
    trait_type_walker: ty::walk::TypeWalker<'tcx>,
    impl_type_walker: ty::walk::TypeWalker<'tcx>,
}

impl<'a, 'tcx> Visitor<'tcx> for TraitImplTyVisitor<'a, 'tcx> {
    fn visit_ty(&mut self, t: &'tcx Ty) {
        let trait_ty = self.trait_type_walker.next();
        let impl_ty = self.impl_type_walker.next();

        if let TyKind::Path(QPath::Resolved(_, path)) = &t.node {
            // The implementation and trait types don't match which means that
            // the concrete type was specified by the implementation
            if impl_ty != trait_ty {
                if let Some(impl_ty) = impl_ty {
                    if self.item_type == impl_ty {
                        let is_self_ty = if let def::Def::SelfTy(..) = path.def {
                            true
                        } else {
                            false
                        };

                        if !is_self_ty {
                            span_use_self_lint(self.cx, path);
                        }
                    }
                }
            }
        }

        walk_ty(self, t)
    }

    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
        NestedVisitorMap::None
    }
}

fn check_trait_method_impl_decl<'a, 'tcx: 'a>(
    cx: &'a LateContext<'a, 'tcx>,
    item_type: ty::Ty<'tcx>,
    impl_item: &ImplItem,
    impl_decl: &'tcx FnDecl,
    impl_trait_ref: &ty::TraitRef<'_>,
) {
    let trait_method = cx
        .tcx
        .associated_items(impl_trait_ref.def_id)
        .find(|assoc_item| {
            assoc_item.kind == ty::AssociatedKind::Method
                && cx
                    .tcx
                    .hygienic_eq(impl_item.ident, assoc_item.ident, impl_trait_ref.def_id)
        })
        .expect("impl method matches a trait method");

    let trait_method_sig = cx.tcx.fn_sig(trait_method.def_id);
    let trait_method_sig = cx.tcx.erase_late_bound_regions(&trait_method_sig);

    let impl_method_def_id = cx.tcx.hir().local_def_id(impl_item.id);
    let impl_method_sig = cx.tcx.fn_sig(impl_method_def_id);
    let impl_method_sig = cx.tcx.erase_late_bound_regions(&impl_method_sig);

    let output_ty = if let FunctionRetTy::Return(ty) = &impl_decl.output {
        Some(&**ty)
    } else {
        None
    };

    // `impl_decl_ty` (of type `hir::Ty`) represents the type declared in the signature.
    // `impl_ty` (of type `ty:TyS`) is the concrete type that the compiler has determined for
    // that declaration.  We use `impl_decl_ty` to see if the type was declared as `Self`
    // and use `impl_ty` to check its concrete type.
    for (impl_decl_ty, (impl_ty, trait_ty)) in impl_decl.inputs.iter().chain(output_ty).zip(
        impl_method_sig
            .inputs_and_output
            .iter()
            .zip(trait_method_sig.inputs_and_output),
    ) {
        let mut visitor = TraitImplTyVisitor {
            cx,
            item_type,
            trait_type_walker: trait_ty.walk(),
            impl_type_walker: impl_ty.walk(),
        };

        visitor.visit_ty(&impl_decl_ty);
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UseSelf {
    fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
        if in_external_macro(cx.sess(), item.span) {
            return;
        }
        if_chain! {
            if let ItemKind::Impl(.., ref item_type, ref refs) = item.node;
            if let TyKind::Path(QPath::Resolved(_, ref item_path)) = item_type.node;
            then {
                let parameters = &item_path.segments.last().expect(SEGMENTS_MSG).args;
                let should_check = if let Some(ref params) = *parameters {
                    !params.parenthesized && !params.args.iter().any(|arg| match arg {
                        GenericArg::Lifetime(_) => true,
                        GenericArg::Type(_) => false,
                    })
                } else {
                    true
                };

                if should_check {
                    let visitor = &mut UseSelfVisitor {
                        item_path,
                        cx,
                    };
                    let impl_def_id = cx.tcx.hir().local_def_id(item.id);
                    let impl_trait_ref = cx.tcx.impl_trait_ref(impl_def_id);

                    if let Some(impl_trait_ref) = impl_trait_ref {
                        for impl_item_ref in refs {
                            let impl_item = cx.tcx.hir().impl_item(impl_item_ref.id);
                            if let ImplItemKind::Method(MethodSig{ decl: impl_decl, .. }, impl_body_id)
                                    = &impl_item.node {
                                let item_type = cx.tcx.type_of(impl_def_id);
                                check_trait_method_impl_decl(cx, item_type, impl_item, impl_decl, &impl_trait_ref);

                                let body = cx.tcx.hir().body(*impl_body_id);
                                visitor.visit_body(body);
                            } else {
                                visitor.visit_impl_item(impl_item);
                            }
                        }
                    } else {
                        for impl_item_ref in refs {
                            let impl_item = cx.tcx.hir().impl_item(impl_item_ref.id);
                            visitor.visit_impl_item(impl_item);
                        }
                    }
                }
            }
        }
    }
}

struct UseSelfVisitor<'a, 'tcx: 'a> {
    item_path: &'a Path,
    cx: &'a LateContext<'a, 'tcx>,
}

impl<'a, 'tcx> Visitor<'tcx> for UseSelfVisitor<'a, 'tcx> {
    fn visit_path(&mut self, path: &'tcx Path, _id: HirId) {
        if path.segments.last().expect(SEGMENTS_MSG).ident.name != SelfUpper.name() {
            if self.item_path.def == path.def {
                span_use_self_lint(self.cx, path);
            } else if let Def::StructCtor(ctor_did, CtorKind::Fn) = path.def {
                if self.item_path.def.opt_def_id() == self.cx.tcx.parent_def_id(ctor_did) {
                    span_use_self_lint(self.cx, path);
                }
            }
        }
        walk_path(self, path);
    }

    fn visit_item(&mut self, item: &'tcx Item) {
        match item.node {
            ItemKind::Use(..)
            | ItemKind::Static(..)
            | ItemKind::Enum(..)
            | ItemKind::Struct(..)
            | ItemKind::Union(..)
            | ItemKind::Impl(..) => {
                // Don't check statements that shadow `Self` or where `Self` can't be used
            },
            _ => walk_item(self, item),
        }
    }

    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
        NestedVisitorMap::All(&self.cx.tcx.hir())
    }
}
<commit_msg>Improve span shortening.<commit_after>use crate::utils::span_lint_and_sugg;
use if_chain::if_chain;
use rustc::hir::def::{CtorKind, Def};
use rustc::hir::intravisit::{walk_item, walk_path, walk_ty, NestedVisitorMap, Visitor};
use rustc::hir::*;
use rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
use rustc::ty;
use rustc::{declare_tool_lint, lint_array};
use rustc_errors::Applicability;
use syntax_pos::symbol::keywords::SelfUpper;

/// **What it does:** Checks for unnecessary repetition of structure name when a
/// replacement with `Self` is applicable.
///
/// **Why is this bad?** Unnecessary repetition. Mixed use of `Self` and struct
/// name
/// feels inconsistent.
///
/// **Known problems:**
/// - False positive when using associated types (#2843)
/// - False positives in some situations when using generics (#3410)
///
/// **Example:**
/// ```rust
/// struct Foo {}
/// impl Foo {
///     fn new() -> Foo {
///         Foo {}
///     }
/// }
/// ```
/// could be
/// ```rust
/// struct Foo {}
/// impl Foo {
///     fn new() -> Self {
///         Self {}
///     }
/// }
/// ```
declare_clippy_lint! {
    pub USE_SELF,
    pedantic,
    "Unnecessary structure name repetition whereas `Self` is applicable"
}

#[derive(Copy, Clone, Default)]
pub struct UseSelf;

impl LintPass for UseSelf {
    fn get_lints(&self) -> LintArray {
        lint_array!(USE_SELF)
    }
}

const SEGMENTS_MSG: &str = "segments should be composed of at least 1 element";

fn span_use_self_lint(cx: &LateContext<'_, '_>, path: &Path) {
    // path segments only include actual path, no methods or fields
    let last_path_span = path.segments.last().expect(SEGMENTS_MSG).ident.span;
    // `to()` doesn't shorten span, so we shorten it with `until(..)`
    // and then include it with `to(..)`
    let span = path.span.with_hi(last_path_span.hi());

    span_lint_and_sugg(
        cx,
        USE_SELF,
        span,
        "unnecessary structure name repetition",
        "use the applicable keyword",
        "Self".to_owned(),
        Applicability::MachineApplicable,
    );
}

struct TraitImplTyVisitor<'a, 'tcx: 'a> {
    item_type: ty::Ty<'tcx>,
    cx: &'a LateContext<'a, 'tcx>,
    trait_type_walker: ty::walk::TypeWalker<'tcx>,
    impl_type_walker: ty::walk::TypeWalker<'tcx>,
}

impl<'a, 'tcx> Visitor<'tcx> for TraitImplTyVisitor<'a, 'tcx> {
    fn visit_ty(&mut self, t: &'tcx Ty) {
        let trait_ty = self.trait_type_walker.next();
        let impl_ty = self.impl_type_walker.next();

        if let TyKind::Path(QPath::Resolved(_, path)) = &t.node {
            // The implementation and trait types don't match which means that
            // the concrete type was specified by the implementation
            if impl_ty != trait_ty {
                if let Some(impl_ty) = impl_ty {
                    if self.item_type == impl_ty {
                        let is_self_ty = if let def::Def::SelfTy(..) = path.def {
                            true
                        } else {
                            false
                        };

                        if !is_self_ty {
                            span_use_self_lint(self.cx, path);
                        }
                    }
                }
            }
        }

        walk_ty(self, t)
    }

    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
        NestedVisitorMap::None
    }
}

fn check_trait_method_impl_decl<'a, 'tcx: 'a>(
    cx: &'a LateContext<'a, 'tcx>,
    item_type: ty::Ty<'tcx>,
    impl_item: &ImplItem,
    impl_decl: &'tcx FnDecl,
    impl_trait_ref: &ty::TraitRef<'_>,
) {
    let trait_method = cx
        .tcx
        .associated_items(impl_trait_ref.def_id)
        .find(|assoc_item| {
            assoc_item.kind == ty::AssociatedKind::Method
                && cx
                    .tcx
                    .hygienic_eq(impl_item.ident, assoc_item.ident, impl_trait_ref.def_id)
        })
        .expect("impl method matches a trait method");

    let trait_method_sig = cx.tcx.fn_sig(trait_method.def_id);
    let trait_method_sig = cx.tcx.erase_late_bound_regions(&trait_method_sig);

    let impl_method_def_id = cx.tcx.hir().local_def_id(impl_item.id);
    let impl_method_sig = cx.tcx.fn_sig(impl_method_def_id);
    let impl_method_sig = cx.tcx.erase_late_bound_regions(&impl_method_sig);

    let output_ty = if let FunctionRetTy::Return(ty) = &impl_decl.output {
        Some(&**ty)
    } else {
        None
    };

    // `impl_decl_ty` (of type `hir::Ty`) represents the type declared in the signature.
    // `impl_ty` (of type `ty:TyS`) is the concrete type that the compiler has determined for
    // that declaration.  We use `impl_decl_ty` to see if the type was declared as `Self`
    // and use `impl_ty` to check its concrete type.
    for (impl_decl_ty, (impl_ty, trait_ty)) in impl_decl.inputs.iter().chain(output_ty).zip(
        impl_method_sig
            .inputs_and_output
            .iter()
            .zip(trait_method_sig.inputs_and_output),
    ) {
        let mut visitor = TraitImplTyVisitor {
            cx,
            item_type,
            trait_type_walker: trait_ty.walk(),
            impl_type_walker: impl_ty.walk(),
        };

        visitor.visit_ty(&impl_decl_ty);
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UseSelf {
    fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
        if in_external_macro(cx.sess(), item.span) {
            return;
        }
        if_chain! {
            if let ItemKind::Impl(.., ref item_type, ref refs) = item.node;
            if let TyKind::Path(QPath::Resolved(_, ref item_path)) = item_type.node;
            then {
                let parameters = &item_path.segments.last().expect(SEGMENTS_MSG).args;
                let should_check = if let Some(ref params) = *parameters {
                    !params.parenthesized && !params.args.iter().any(|arg| match arg {
                        GenericArg::Lifetime(_) => true,
                        GenericArg::Type(_) => false,
                    })
                } else {
                    true
                };

                if should_check {
                    let visitor = &mut UseSelfVisitor {
                        item_path,
                        cx,
                    };
                    let impl_def_id = cx.tcx.hir().local_def_id(item.id);
                    let impl_trait_ref = cx.tcx.impl_trait_ref(impl_def_id);

                    if let Some(impl_trait_ref) = impl_trait_ref {
                        for impl_item_ref in refs {
                            let impl_item = cx.tcx.hir().impl_item(impl_item_ref.id);
                            if let ImplItemKind::Method(MethodSig{ decl: impl_decl, .. }, impl_body_id)
                                    = &impl_item.node {
                                let item_type = cx.tcx.type_of(impl_def_id);
                                check_trait_method_impl_decl(cx, item_type, impl_item, impl_decl, &impl_trait_ref);

                                let body = cx.tcx.hir().body(*impl_body_id);
                                visitor.visit_body(body);
                            } else {
                                visitor.visit_impl_item(impl_item);
                            }
                        }
                    } else {
                        for impl_item_ref in refs {
                            let impl_item = cx.tcx.hir().impl_item(impl_item_ref.id);
                            visitor.visit_impl_item(impl_item);
                        }
                    }
                }
            }
        }
    }
}

struct UseSelfVisitor<'a, 'tcx: 'a> {
    item_path: &'a Path,
    cx: &'a LateContext<'a, 'tcx>,
}

impl<'a, 'tcx> Visitor<'tcx> for UseSelfVisitor<'a, 'tcx> {
    fn visit_path(&mut self, path: &'tcx Path, _id: HirId) {
        if path.segments.last().expect(SEGMENTS_MSG).ident.name != SelfUpper.name() {
            if self.item_path.def == path.def {
                span_use_self_lint(self.cx, path);
            } else if let Def::StructCtor(ctor_did, CtorKind::Fn) = path.def {
                if self.item_path.def.opt_def_id() == self.cx.tcx.parent_def_id(ctor_did) {
                    span_use_self_lint(self.cx, path);
                }
            }
        }
        walk_path(self, path);
    }

    fn visit_item(&mut self, item: &'tcx Item) {
        match item.node {
            ItemKind::Use(..)
            | ItemKind::Static(..)
            | ItemKind::Enum(..)
            | ItemKind::Struct(..)
            | ItemKind::Union(..)
            | ItemKind::Impl(..) => {
                // Don't check statements that shadow `Self` or where `Self` can't be used
            },
            _ => walk_item(self, item),
        }
    }

    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
        NestedVisitorMap::All(&self.cx.tcx.hir())
    }
}
<|endoftext|>


<commit_before>use std::io::{self, Write};
use ir;

pub fn emit_program<W: Write>(program: &ir::Program, mut out: W) -> io::Result<()> {
    for (name, func) in &program.functions {
        write!(out, "function {}", name.0)?;
        emit_function(func, &mut out)?;
        writeln!(out)?;
    }
    Ok(())
}

fn emit_function<W: Write>(func: &ir::Function, out: &mut W) -> io::Result<()> {
    write!(out, "(")?;
    let mut first = true;
    for param in &func.parameters {
        if !first { write!(out, ", ")?; }
        first = false;
        write!(out, "%{}", param.0)?;
    }
    write!(out, ")")?;
    if let Some(layout) = func.output_layout {
        writeln!(out, ": {{ {}, {} }}", layout.size, layout.align)?;
    } else {
        writeln!(out)?;
    }
    for (reg, layout) in &func.registers {
        writeln!(out, "    register %{}: size {}, align {}", reg.0, layout.size, layout.align)?;
    }
    if func.start_block.is_none() {
        return Ok(());
    }
    writeln!(out, "start:")?;
    writeln!(out, "    goto label_{}:", func.start_block.unwrap().0)?;
    for (id, block) in &func.blocks {
        writeln!(out, "label_{}:", id.0)?;
        for op in &block.ops {
            emit_instruction(op, out)?;
        }
        match block.end {
            ir::BlockEnd::Branch(ref val, a, b) => {
                write!(out, "    branch ")?;
                emit_value(val, out)?;
                writeln!(out, " label_{} label_{}", a.0, b.0)?;
            }
            ir::BlockEnd::Jump(id) => {
                writeln!(out, "    goto label_{}", id.0)?;
            }
            ir::BlockEnd::Return(ref val) => {
                write!(out, "    return ")?;
                emit_value(val, out)?;
                writeln!(out)?;
            }
            ir::BlockEnd::ReturnProc => {
                writeln!(out, "    return")?;
            }
        }
    }
    Ok(())
}

fn emit_instruction<W: Write>(i: &ir::Instruction, out: &mut W) -> io::Result<()> {
    match *i {
        ir::Instruction::Assign(reg, ref val) => {
            write!(out, "    %{} = ", reg.0)?;
            emit_value(val, out)?;
            writeln!(out)
        }
        ir::Instruction::BinaryOp(dest, op, ref a, ref b) => {
            write!(out, "    %{} = ", dest.0)?;
            emit_binop(op, out)?;
            write!(out, " ")?;
            emit_value(a, out)?;
            write!(out, " ")?;
            emit_value(b, out)?;
            writeln!(out)
        }
        ir::Instruction::Call(dest, ref sym, ref params) => {
            write!(out, "    %{} = call {}", dest.0, sym.0)?;
            emit_params(params, out)?;
            writeln!(out)
        }
        ir::Instruction::CallProc(ref sym, ref params) => {
            write!(out, "    call {}", sym.0)?;
            emit_params(params, out)?;
            writeln!(out)
        }
        ir::Instruction::CallVirt(dest, ref val, ref params) => {
            write!(out, "    %{} = callvirt ", dest.0)?;
            emit_value(val, out)?;
            emit_params(params, out)?;
            writeln!(out)
        }
        ir::Instruction::CallProcVirt(ref val, ref params) => {
            write!(out, "    callvirt ")?;
            emit_value(val, out)?;
            emit_params(params, out)?;
            writeln!(out)
        }
        ir::Instruction::DerefLoad(dest, ref value, offset) => {
            write!(out, "    %{} = deref (", dest.0)?;
            emit_value(value, out)?;
            writeln!(out, " + {})", offset)
        }
        ir::Instruction::DerefStore(ref address, offset, ref value) => {
            write!(out, "    store (")?;
            emit_value(address, out)?;
            write!(out, " + {}) ", offset)?;
            emit_value(value, out)?;
            writeln!(out)
        }
        ir::Instruction::Drop(reg) => {
            writeln!(out, "    drop %{}", reg.0)
        }
        ir::Instruction::Load(dest, reg, offset) => {
            writeln!(out, "    %{} = %{}[{}]", dest.0, reg.0, offset)
        }
        ir::Instruction::Store(dest, offset, ref value) => {
            write!(out, "    %{}[{}] = ", dest.0, offset)?;
            emit_value(value, out)?;
            writeln!(out)
        }
        ir::Instruction::TakeAddress(dest, of, offset) => {
            writeln!(out, "    %{} = address %{}[{}]", dest.0, of.0, offset)
        }
        ir::Instruction::UnaryOp(dest, ir::UnaryOp::Negate(sign, size), ref arg) => {
            write!(out, "    %{} = neg_", dest.0)?;
            emit_sign(sign, out)?;
            emit_size(size, out)?;
            write!(out, " ")?;
            emit_value(arg, out)?;
            writeln!(out)
        }
    }
}

fn emit_value<W: Write>(val: &ir::Value, out: &mut W) -> io::Result<()> {
    match *val {
        ir::Value::Bytes(ref bytes) => {
            write!(out, "\"")?;
            for &byte in bytes {
                if byte < 32 || byte > 126 {
                    write!(out, "\\x{:x}", byte)?;
                } else if byte == b'"' {
                    write!(out, "\\\"")?;
                } else {
                    write!(out, "{}", byte as char)?;
                }
            }
            write!(out, "\"")
        }
        ir::Value::Int(value, size) => {
            match size {
                ir::Size::Bit8 => write!(out, "{}_b8", value),
                ir::Size::Bit16 => write!(out, "{}_b16", value),
                ir::Size::Bit32 => write!(out, "{}_b32", value),
            }
        }
        ir::Value::Reg(reg) => {
            write!(out, "%{}", reg.0)
        }
        ir::Value::Symbol(ref sym) => {
            write!(out, "{}", sym.0)
        }
    }
}

fn emit_binop<W: Write>(op: ir::BinaryOp, out: &mut W) -> io::Result<()> {
    match op {
        ir::BinaryOp::BitOp(ir::BitOp::And, s) => {
            write!(out, "and_")?;
            emit_size(s, out)
        }
        ir::BinaryOp::BitOp(ir::BitOp::Or, s) => {
            write!(out, "or_")?;
            emit_size(s, out)
        }
        ir::BinaryOp::BitOp(ir::BitOp::Xor, s) => {
            write!(out, "xor_")?;
            emit_size(s, out)
        }
        ir::BinaryOp::Eq => {
            write!(out, "eq")
        }
        ir::BinaryOp::Neq => {
            write!(out, "neq")
        }
        ir::BinaryOp::IntOp(ir::IntOp::Add, sign, size) => {
            write!(out, "add_")?;
            emit_sign(sign, out)?;
            emit_size(size, out)
        }
        ir::BinaryOp::IntOp(ir::IntOp::Div, sign, size) => {
            write!(out, "div_")?;
            emit_sign(sign, out)?;
            emit_size(size, out)
        }
        ir::BinaryOp::IntOp(ir::IntOp::Greater, sign, size) => {
            write!(out, "gt_")?;
            emit_sign(sign, out)?;
            emit_size(size, out)
        }
        ir::BinaryOp::IntOp(ir::IntOp::GreaterEq, sign, size) => {
            write!(out, "geq_")?;
            emit_sign(sign, out)?;
            emit_size(size, out)
        }
        ir::BinaryOp::IntOp(ir::IntOp::Less, sign, size) => {
            write!(out, "le_")?;
            emit_sign(sign, out)?;
            emit_size(size, out)
        }
        ir::BinaryOp::IntOp(ir::IntOp::LessEq, sign, size) => {
            write!(out, "leq_")?;
            emit_sign(sign, out)?;
            emit_size(size, out)
        }
        ir::BinaryOp::IntOp(ir::IntOp::Mod, sign, size) => {
            write!(out, "mod_")?;
            emit_sign(sign, out)?;
            emit_size(size, out)
        }
        ir::BinaryOp::IntOp(ir::IntOp::Mul, sign, size) => {
            write!(out, "mul_")?;
            emit_sign(sign, out)?;
            emit_size(size, out)
        }
        ir::BinaryOp::IntOp(ir::IntOp::Sub, sign, size) => {
            write!(out, "sub_")?;
            emit_sign(sign, out)?;
            emit_size(size, out)
        }
    }
}

fn emit_sign<W: Write>(sign: ir::Signedness, out: &mut W) -> io::Result<()> {
    match sign {
        ir::Signedness::Unsigned => write!(out, "u"),
        ir::Signedness::Signed => write!(out, "i"),
    }
}

fn emit_size<W: Write>(size: ir::Size, out: &mut W) -> io::Result<()> {
    match size {
        ir::Size::Bit8 => write!(out, "8"),
        ir::Size::Bit16 => write!(out, "16"),
        ir::Size::Bit32 => write!(out, "32"),
    }
}

fn emit_params<W: Write>(params: &[ir::Value], out: &mut W) -> io::Result<()> {
    write!(out, "(")?;
    let mut first = true;
    for param in params {
        if !first { write!(out, ", ")?; }
        first = false;
        emit_value(param, out)?;
    }
    write!(out, ")")
}
<commit_msg>correctly format string escapes in ir<commit_after>use std::io::{self, Write};
use ir;

pub fn emit_program<W: Write>(program: &ir::Program, mut out: W) -> io::Result<()> {
    for (name, func) in &program.functions {
        write!(out, "function {}", name.0)?;
        emit_function(func, &mut out)?;
        writeln!(out)?;
    }
    Ok(())
}

fn emit_function<W: Write>(func: &ir::Function, out: &mut W) -> io::Result<()> {
    write!(out, "(")?;
    let mut first = true;
    for param in &func.parameters {
        if !first { write!(out, ", ")?; }
        first = false;
        write!(out, "%{}", param.0)?;
    }
    write!(out, ")")?;
    if let Some(layout) = func.output_layout {
        writeln!(out, ": {{ {}, {} }}", layout.size, layout.align)?;
    } else {
        writeln!(out)?;
    }
    for (reg, layout) in &func.registers {
        writeln!(out, "    register %{}: size {}, align {}", reg.0, layout.size, layout.align)?;
    }
    if func.start_block.is_none() {
        return Ok(());
    }
    writeln!(out, "start:")?;
    writeln!(out, "    goto label_{}:", func.start_block.unwrap().0)?;
    for (id, block) in &func.blocks {
        writeln!(out, "label_{}:", id.0)?;
        for op in &block.ops {
            emit_instruction(op, out)?;
        }
        match block.end {
            ir::BlockEnd::Branch(ref val, a, b) => {
                write!(out, "    branch ")?;
                emit_value(val, out)?;
                writeln!(out, " label_{} label_{}", a.0, b.0)?;
            }
            ir::BlockEnd::Jump(id) => {
                writeln!(out, "    goto label_{}", id.0)?;
            }
            ir::BlockEnd::Return(ref val) => {
                write!(out, "    return ")?;
                emit_value(val, out)?;
                writeln!(out)?;
            }
            ir::BlockEnd::ReturnProc => {
                writeln!(out, "    return")?;
            }
        }
    }
    Ok(())
}

fn emit_instruction<W: Write>(i: &ir::Instruction, out: &mut W) -> io::Result<()> {
    match *i {
        ir::Instruction::Assign(reg, ref val) => {
            write!(out, "    %{} = ", reg.0)?;
            emit_value(val, out)?;
            writeln!(out)
        }
        ir::Instruction::BinaryOp(dest, op, ref a, ref b) => {
            write!(out, "    %{} = ", dest.0)?;
            emit_binop(op, out)?;
            write!(out, " ")?;
            emit_value(a, out)?;
            write!(out, " ")?;
            emit_value(b, out)?;
            writeln!(out)
        }
        ir::Instruction::Call(dest, ref sym, ref params) => {
            write!(out, "    %{} = call {}", dest.0, sym.0)?;
            emit_params(params, out)?;
            writeln!(out)
        }
        ir::Instruction::CallProc(ref sym, ref params) => {
            write!(out, "    call {}", sym.0)?;
            emit_params(params, out)?;
            writeln!(out)
        }
        ir::Instruction::CallVirt(dest, ref val, ref params) => {
            write!(out, "    %{} = callvirt ", dest.0)?;
            emit_value(val, out)?;
            emit_params(params, out)?;
            writeln!(out)
        }
        ir::Instruction::CallProcVirt(ref val, ref params) => {
            write!(out, "    callvirt ")?;
            emit_value(val, out)?;
            emit_params(params, out)?;
            writeln!(out)
        }
        ir::Instruction::DerefLoad(dest, ref value, offset) => {
            write!(out, "    %{} = deref (", dest.0)?;
            emit_value(value, out)?;
            writeln!(out, " + {})", offset)
        }
        ir::Instruction::DerefStore(ref address, offset, ref value) => {
            write!(out, "    store (")?;
            emit_value(address, out)?;
            write!(out, " + {}) ", offset)?;
            emit_value(value, out)?;
            writeln!(out)
        }
        ir::Instruction::Drop(reg) => {
            writeln!(out, "    drop %{}", reg.0)
        }
        ir::Instruction::Load(dest, reg, offset) => {
            writeln!(out, "    %{} = %{}[{}]", dest.0, reg.0, offset)
        }
        ir::Instruction::Store(dest, offset, ref value) => {
            write!(out, "    %{}[{}] = ", dest.0, offset)?;
            emit_value(value, out)?;
            writeln!(out)
        }
        ir::Instruction::TakeAddress(dest, of, offset) => {
            writeln!(out, "    %{} = address %{}[{}]", dest.0, of.0, offset)
        }
        ir::Instruction::UnaryOp(dest, ir::UnaryOp::Negate(sign, size), ref arg) => {
            write!(out, "    %{} = neg_", dest.0)?;
            emit_sign(sign, out)?;
            emit_size(size, out)?;
            write!(out, " ")?;
            emit_value(arg, out)?;
            writeln!(out)
        }
    }
}

fn emit_value<W: Write>(val: &ir::Value, out: &mut W) -> io::Result<()> {
    match *val {
        ir::Value::Bytes(ref bytes) => {
            write!(out, "\"")?;
            for &byte in bytes {
                if byte < 32 || byte > 126 {
                    write!(out, "\\x{:0>2x}", byte)?;
                } else if byte == b'"' {
                    write!(out, "\\\"")?;
                } else {
                    write!(out, "{}", byte as char)?;
                }
            }
            write!(out, "\"")
        }
        ir::Value::Int(value, size) => {
            match size {
                ir::Size::Bit8 => write!(out, "{}_b8", value),
                ir::Size::Bit16 => write!(out, "{}_b16", value),
                ir::Size::Bit32 => write!(out, "{}_b32", value),
            }
        }
        ir::Value::Reg(reg) => {
            write!(out, "%{}", reg.0)
        }
        ir::Value::Symbol(ref sym) => {
            write!(out, "{}", sym.0)
        }
    }
}

fn emit_binop<W: Write>(op: ir::BinaryOp, out: &mut W) -> io::Result<()> {
    match op {
        ir::BinaryOp::BitOp(ir::BitOp::And, s) => {
            write!(out, "and_")?;
            emit_size(s, out)
        }
        ir::BinaryOp::BitOp(ir::BitOp::Or, s) => {
            write!(out, "or_")?;
            emit_size(s, out)
        }
        ir::BinaryOp::BitOp(ir::BitOp::Xor, s) => {
            write!(out, "xor_")?;
            emit_size(s, out)
        }
        ir::BinaryOp::Eq => {
            write!(out, "eq")
        }
        ir::BinaryOp::Neq => {
            write!(out, "neq")
        }
        ir::BinaryOp::IntOp(ir::IntOp::Add, sign, size) => {
            write!(out, "add_")?;
            emit_sign(sign, out)?;
            emit_size(size, out)
        }
        ir::BinaryOp::IntOp(ir::IntOp::Div, sign, size) => {
            write!(out, "div_")?;
            emit_sign(sign, out)?;
            emit_size(size, out)
        }
        ir::BinaryOp::IntOp(ir::IntOp::Greater, sign, size) => {
            write!(out, "gt_")?;
            emit_sign(sign, out)?;
            emit_size(size, out)
        }
        ir::BinaryOp::IntOp(ir::IntOp::GreaterEq, sign, size) => {
            write!(out, "geq_")?;
            emit_sign(sign, out)?;
            emit_size(size, out)
        }
        ir::BinaryOp::IntOp(ir::IntOp::Less, sign, size) => {
            write!(out, "le_")?;
            emit_sign(sign, out)?;
            emit_size(size, out)
        }
        ir::BinaryOp::IntOp(ir::IntOp::LessEq, sign, size) => {
            write!(out, "leq_")?;
            emit_sign(sign, out)?;
            emit_size(size, out)
        }
        ir::BinaryOp::IntOp(ir::IntOp::Mod, sign, size) => {
            write!(out, "mod_")?;
            emit_sign(sign, out)?;
            emit_size(size, out)
        }
        ir::BinaryOp::IntOp(ir::IntOp::Mul, sign, size) => {
            write!(out, "mul_")?;
            emit_sign(sign, out)?;
            emit_size(size, out)
        }
        ir::BinaryOp::IntOp(ir::IntOp::Sub, sign, size) => {
            write!(out, "sub_")?;
            emit_sign(sign, out)?;
            emit_size(size, out)
        }
    }
}

fn emit_sign<W: Write>(sign: ir::Signedness, out: &mut W) -> io::Result<()> {
    match sign {
        ir::Signedness::Unsigned => write!(out, "u"),
        ir::Signedness::Signed => write!(out, "i"),
    }
}

fn emit_size<W: Write>(size: ir::Size, out: &mut W) -> io::Result<()> {
    match size {
        ir::Size::Bit8 => write!(out, "8"),
        ir::Size::Bit16 => write!(out, "16"),
        ir::Size::Bit32 => write!(out, "32"),
    }
}

fn emit_params<W: Write>(params: &[ir::Value], out: &mut W) -> io::Result<()> {
    write!(out, "(")?;
    let mut first = true;
    for param in params {
        if !first { write!(out, ", ")?; }
        first = false;
        emit_value(param, out)?;
    }
    write!(out, ")")
}
<|endoftext|>