<commit_before>//! rustdoc handler

use super::pool::Pool;
use super::file::File;
use super::{latest_version, redirect_base};
use super::crate_details::CrateDetails;
use iron::prelude::*;
use iron::{status, Url};
use iron::modifiers::Redirect;
use router::Router;
use super::{match_version, MatchVersion};
use super::error::Nope;
use super::page::Page;
use rustc_serialize::json::{Json, ToJson};
use std::collections::BTreeMap;
use iron::headers::{Expires, HttpDate, CacheControl, CacheDirective};
use postgres::Connection;
use time;
use iron::Handler;
use utils;

#[derive(Debug)]
struct RustdocPage {
    pub head: String,
    pub body: String,
    pub body_class: String,
    pub name: String,
    pub full: String,
    pub version: String,
    pub description: Option<String>,
    pub crate_details: Option<CrateDetails>,
}

impl Default for RustdocPage {
    fn default() -> RustdocPage {
        RustdocPage {
            head: String::new(),
            body: String::new(),
            body_class: String::new(),
            name: String::new(),
            full: String::new(),
            version: String::new(),
            description: None,
            crate_details: None,
        }
    }
}

impl ToJson for RustdocPage {
    fn to_json(&self) -> Json {
        let mut m: BTreeMap<String, Json> = BTreeMap::new();
        m.insert("rustdoc_head".to_string(), self.head.to_json());
        m.insert("rustdoc_body".to_string(), self.body.to_json());
        m.insert("rustdoc_body_class".to_string(), self.body_class.to_json());
        m.insert("rustdoc_full".to_string(), self.full.to_json());
        m.insert("rustdoc_status".to_string(), true.to_json());
        m.insert("name".to_string(), self.name.to_json());
        m.insert("version".to_string(), self.version.to_json());
        m.insert("description".to_string(), self.description.to_json());
        m.insert("crate_details".to_string(), self.crate_details.to_json());
        m.to_json()
    }
}

pub struct RustLangRedirector {
    url: Url,
}

impl RustLangRedirector {
    pub fn new(target: &'static str) -> Self {
        let url = url::Url::parse("https://doc.rust-lang.org/stable/")
            .expect("failed to parse rust-lang.org base URL")
            .join(target)
            .expect("failed to append crate name to rust-lang.org base URL");
        let url = Url::from_generic_url(url)
            .expect("failed to convert url::Url to iron::Url");
        Self { url }
    }
}

impl iron::Handler for RustLangRedirector {
    fn handle(&self, _req: &mut Request) -> IronResult<Response> {
        Ok(Response::with((status::Found, Redirect(self.url.clone()))))
    }
}

/// Handler called for `/:crate` and `/:crate/:version` URLs. Automatically redirects to the docs
/// or crate details page based on whether the given crate version was successfully built.
pub fn rustdoc_redirector_handler(req: &mut Request) -> IronResult<Response> {

    fn redirect_to_doc(req: &Request,
                       name: &str,
                       vers: &str,
                       target_name: &str)
                       -> IronResult<Response> {
        let url = ctry!(Url::parse(&format!("{}/{}/{}/{}/",
                                            redirect_base(req),
                                            name,
                                            vers,
                                            target_name)[..]));
        let mut resp = Response::with((status::Found, Redirect(url)));
        resp.headers.set(Expires(HttpDate(time::now())));

        Ok(resp)
    }

    fn redirect_to_crate(req: &Request,
                         name: &str,
                         vers: &str)
                         -> IronResult<Response> {
        let url = ctry!(Url::parse(&format!("{}/crate/{}/{}",
                                            redirect_base(req),
                                            name,
                                            vers)[..]));

        let mut resp = Response::with((status::Found, Redirect(url)));
        resp.headers.set(Expires(HttpDate(time::now())));

        Ok(resp)
    }

    // this unwrap is safe because iron urls are always able to use `path_segments`
    // i'm using this instead of `req.url.path()` to avoid allocating the Vec, and also to avoid
    // keeping the borrow alive into the return statement
    if req.url.as_ref().path_segments().unwrap().last().map_or(false, |s| s.ends_with(".js")) {
        // javascript files should be handled by the file server instead of erroneously
        // redirecting to the crate root page
        if req.url.as_ref().path_segments().unwrap().count() > 2 {
            // this URL is actually from a crate-internal path, serve it there instead
            return rustdoc_html_server_handler(req);
        } else {
            let path = req.url.path();
            let path = path.join("/");
            let conn = extension!(req, Pool);
            match File::from_path(&conn, &path) {
                Some(f) => return Ok(f.serve()),
                None => return Err(IronError::new(Nope::ResourceNotFound, status::NotFound)),
            }
        }
    } else if req.url.as_ref().path_segments().unwrap().last().map_or(false, |s| s.ends_with(".ico")) {
        // route .ico files into their dedicated handler so that docs.rs's favicon is always
        // displayed
        return super::ico_handler(req);
    }

    let router = extension!(req, Router);
    // this handler should never called without crate pattern
    let crate_name = cexpect!(router.find("crate"));
    let req_version = router.find("version");

    let conn = extension!(req, Pool);

    // it doesn't matter if the version that was given was exact or not, since we're redirecting
    // anyway
    let version = match match_version(&conn, &crate_name, req_version).into_option() {
        Some(v) => v,
        None => return Err(IronError::new(Nope::CrateNotFound, status::NotFound)),
    };

    // get target name and whether it has docs
    // FIXME: This is a bit inefficient but allowing us to use less code in general
    let (target_name, has_docs): (String, bool) = {
        let rows = ctry!(conn.query("SELECT target_name, rustdoc_status
                                     FROM releases
                                     INNER JOIN crates ON crates.id = releases.crate_id
                                     WHERE crates.name = $1 AND releases.version = $2",
                                    &[&crate_name, &version]));

        (rows.get(0).get(0), rows.get(0).get(1))
    };

    if has_docs {
        redirect_to_doc(req, &crate_name, &version, &target_name)
    } else {
        redirect_to_crate(req, &crate_name, &version)
    }
}

/// Serves documentation generated by rustdoc.
///
/// This includes all HTML files for an individual crate, as well as the `search-index.js`, which is
/// also crate-specific.
pub fn rustdoc_html_server_handler(req: &mut Request) -> IronResult<Response> {

    let router = extension!(req, Router);
    let name = router.find("crate").unwrap_or("").to_string();
    let url_version = router.find("version");
    let version; // pre-declaring it to enforce drop order relative to `req_path`
    let conn = extension!(req, Pool);

    let mut req_path = req.url.path();

    // remove name and version from path
    for _ in 0..2 {
        req_path.remove(0);
    }

    version = match match_version(&conn, &name, url_version) {
        MatchVersion::Exact(v) => v,
        MatchVersion::Semver(v) => {
            // to prevent cloudfront caching the wrong artifacts on URLs with loose semver
            // versions, redirect the browser to the returned version instead of loading it
            // immediately
            let url = ctry!(Url::parse(&format!("{}/{}/{}/{}",
                                                redirect_base(req),
                                                name,
                                                v,
                                                req_path.join("/"))[..]));
            return Ok(super::redirect(url));
        }
        MatchVersion::None => return Err(IronError::new(Nope::ResourceNotFound, status::NotFound)),
    };

    // docs have "rustdoc" prefix in database
    req_path.insert(0, "rustdoc");

    // add crate name and version
    req_path.insert(1, &name);
    req_path.insert(2, &version);

    let path = {
        let mut path = req_path.join("/");
        if path.ends_with('/') {
            req_path.pop(); // get rid of empty string
            path.push_str("index.html");
            req_path.push("index.html");
        }
        path
    };

    let file = match File::from_path(&conn, &path) {
        Some(f) => f,
        None => return Err(IronError::new(Nope::ResourceNotFound, status::NotFound)),
    };

    // serve file directly if it's not html
    if !path.ends_with(".html") {
        return Ok(file.serve());
    }

    let mut content = RustdocPage::default();

    let file_content = ctry!(String::from_utf8(file.0.content));

    let (head, body, mut body_class) = ctry!(utils::extract_head_and_body(&file_content));
    content.head = head;
    content.body = body;

    if body_class.is_empty() {
        body_class = "rustdoc container-rustdoc".to_string();
    } else {
        // rustdoc adds its own "rustdoc" class to the body
        body_class.push_str(" container-rustdoc");
    }
    content.body_class = body_class;

    content.full = file_content;
    let crate_details = cexpect!(CrateDetails::new(&conn, &name, &version));
    let (path, version) = if let Some(version) = latest_version(&crate_details.versions, &version) {
        req_path[2] = &version;
        (path_for_version(&req_path, &crate_details.target_name, &conn), version)
    } else {
        Default::default()
    };

    content.crate_details = Some(crate_details);

    Page::new(content)
        .set_true("show_package_navigation")
        .set_true("package_navigation_documentation_tab")
        .set_true("package_navigation_show_platforms_tab")
        .set_bool("is_latest_version", path.is_empty())
        .set("path_in_latest", &path)
        .set("latest_version", &version)
        .to_resp("rustdoc")
}

/// Checks whether the given path (including version and target information) exists.
/// The crate's `target_name` is used to confirm whether a platform triple is part of the path.
///
/// Returns a path that can be appended to `/crate/version/` to create a complete URL.
fn path_for_version(req_path: &[&str], target_name: &str, conn: &Connection) -> String {
    // Simple case: page exists in the latest version, so just change the version number
    if File::from_path(&conn, &req_path.join("/")).is_some() {
        // NOTE: this adds 'index.html' if it wasn't there before
        return req_path[3..].join("/");
    }
    // this page doesn't exist in the latest version
    let search_item = if *req_path.last().unwrap() == "index.html" {
        // this is a module
        req_path[req_path.len() - 2]
    } else {
        // this is an item
        req_path.last().unwrap().split('.').nth(1)
            .expect("paths should be of the form <class>.<name>.html")
    };
    // check if req_path[3] is the platform choice or the name of the crate
    let concat_path;
    let crate_root = if req_path[3] != target_name {
        concat_path = format!("{}/{}", req_path[3], req_path[4]);
        &concat_path
    } else {
        req_path[3]
    };
    format!("{}/?search={}", crate_root, search_item)
}

pub fn badge_handler(req: &mut Request) -> IronResult<Response> {
    use iron::headers::ContentType;
    use params::{Params, Value};
    use badge::{Badge, BadgeOptions};

    let version = {
        let params = ctry!(req.get_ref::<Params>());
        match params.find(&["version"]) {
            Some(&Value::String(ref version)) => version.clone(),
            _ => "*".to_owned(),
        }
    };

    let name = cexpect!(extension!(req, Router).find("crate"));
    let conn = extension!(req, Pool);

    let options = match match_version(&conn, &name, Some(&version)) {
        MatchVersion::Exact(version) => {
            let rows = ctry!(conn.query("SELECT rustdoc_status
                                         FROM releases
                                         INNER JOIN crates ON crates.id = releases.crate_id
                                         WHERE crates.name = $1 AND releases.version = $2",
                                        &[&name, &version]));
            if rows.len() > 0 && rows.get(0).get(0) {
                BadgeOptions {
                    subject: "docs".to_owned(),
                    status: version,
                    color: "#4d76ae".to_owned(),
                }
            } else {
                BadgeOptions {
                    subject: "docs".to_owned(),
                    status: version,
                    color: "#e05d44".to_owned(),
                }
            }
        }
        MatchVersion::Semver(version) => {
            let url = ctry!(Url::parse(&format!("{}/{}/badge.svg?version={}",
                                                redirect_base(req),
                                                name,
                                                version)[..]));

            return Ok(super::redirect(url));
        }
        MatchVersion::None => {
            BadgeOptions {
                subject: "docs".to_owned(),
                status: "no builds".to_owned(),
                color: "#e05d44".to_owned(),
            }
        }
    };

    let mut resp = Response::with((status::Ok, ctry!(Badge::new(options)).to_svg()));
    resp.headers.set(ContentType("image/svg+xml".parse().unwrap()));
    resp.headers.set(Expires(HttpDate(time::now())));
    resp.headers.set(CacheControl(vec![CacheDirective::NoCache,
                                       CacheDirective::NoStore,
                                       CacheDirective::MustRevalidate]));
    Ok(resp)
}

/// Serves shared web resources used by rustdoc-generated documentation.
///
/// This includes common `css` and `js` files that only change when the compiler is updated, but are
/// otherwise the same for all crates documented with that compiler. Those have a custom handler to
/// deduplicate them and save space.
pub struct SharedResourceHandler;

impl Handler for SharedResourceHandler {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        let path = req.url.path();
        let filename = path.last().unwrap();  // unwrap is fine: vector is non-empty
        let suffix = filename.split('.').last().unwrap();  // unwrap is fine: split always works
        if ["js", "css", "woff", "svg"].contains(&suffix) {
            let conn = extension!(req, Pool);

            if let Some(file) = File::from_path(conn, filename) {
                return Ok(file.serve());
            }
        }

        // Just always return a 404 here - the main handler will then try the other handlers
        Err(IronError::new(Nope::ResourceNotFound, status::NotFound))
    }
}
<commit_msg>improve doc-comment some more<commit_after>//! rustdoc handler

use super::pool::Pool;
use super::file::File;
use super::{latest_version, redirect_base};
use super::crate_details::CrateDetails;
use iron::prelude::*;
use iron::{status, Url};
use iron::modifiers::Redirect;
use router::Router;
use super::{match_version, MatchVersion};
use super::error::Nope;
use super::page::Page;
use rustc_serialize::json::{Json, ToJson};
use std::collections::BTreeMap;
use iron::headers::{Expires, HttpDate, CacheControl, CacheDirective};
use postgres::Connection;
use time;
use iron::Handler;
use utils;

#[derive(Debug)]
struct RustdocPage {
    pub head: String,
    pub body: String,
    pub body_class: String,
    pub name: String,
    pub full: String,
    pub version: String,
    pub description: Option<String>,
    pub crate_details: Option<CrateDetails>,
}

impl Default for RustdocPage {
    fn default() -> RustdocPage {
        RustdocPage {
            head: String::new(),
            body: String::new(),
            body_class: String::new(),
            name: String::new(),
            full: String::new(),
            version: String::new(),
            description: None,
            crate_details: None,
        }
    }
}

impl ToJson for RustdocPage {
    fn to_json(&self) -> Json {
        let mut m: BTreeMap<String, Json> = BTreeMap::new();
        m.insert("rustdoc_head".to_string(), self.head.to_json());
        m.insert("rustdoc_body".to_string(), self.body.to_json());
        m.insert("rustdoc_body_class".to_string(), self.body_class.to_json());
        m.insert("rustdoc_full".to_string(), self.full.to_json());
        m.insert("rustdoc_status".to_string(), true.to_json());
        m.insert("name".to_string(), self.name.to_json());
        m.insert("version".to_string(), self.version.to_json());
        m.insert("description".to_string(), self.description.to_json());
        m.insert("crate_details".to_string(), self.crate_details.to_json());
        m.to_json()
    }
}

pub struct RustLangRedirector {
    url: Url,
}

impl RustLangRedirector {
    pub fn new(target: &'static str) -> Self {
        let url = url::Url::parse("https://doc.rust-lang.org/stable/")
            .expect("failed to parse rust-lang.org base URL")
            .join(target)
            .expect("failed to append crate name to rust-lang.org base URL");
        let url = Url::from_generic_url(url)
            .expect("failed to convert url::Url to iron::Url");
        Self { url }
    }
}

impl iron::Handler for RustLangRedirector {
    fn handle(&self, _req: &mut Request) -> IronResult<Response> {
        Ok(Response::with((status::Found, Redirect(self.url.clone()))))
    }
}

/// Handler called for `/:crate` and `/:crate/:version` URLs. Automatically redirects to the docs
/// or crate details page based on whether the given crate version was successfully built.
pub fn rustdoc_redirector_handler(req: &mut Request) -> IronResult<Response> {

    fn redirect_to_doc(req: &Request,
                       name: &str,
                       vers: &str,
                       target_name: &str)
                       -> IronResult<Response> {
        let url = ctry!(Url::parse(&format!("{}/{}/{}/{}/",
                                            redirect_base(req),
                                            name,
                                            vers,
                                            target_name)[..]));
        let mut resp = Response::with((status::Found, Redirect(url)));
        resp.headers.set(Expires(HttpDate(time::now())));

        Ok(resp)
    }

    fn redirect_to_crate(req: &Request,
                         name: &str,
                         vers: &str)
                         -> IronResult<Response> {
        let url = ctry!(Url::parse(&format!("{}/crate/{}/{}",
                                            redirect_base(req),
                                            name,
                                            vers)[..]));

        let mut resp = Response::with((status::Found, Redirect(url)));
        resp.headers.set(Expires(HttpDate(time::now())));

        Ok(resp)
    }

    // this unwrap is safe because iron urls are always able to use `path_segments`
    // i'm using this instead of `req.url.path()` to avoid allocating the Vec, and also to avoid
    // keeping the borrow alive into the return statement
    if req.url.as_ref().path_segments().unwrap().last().map_or(false, |s| s.ends_with(".js")) {
        // javascript files should be handled by the file server instead of erroneously
        // redirecting to the crate root page
        if req.url.as_ref().path_segments().unwrap().count() > 2 {
            // this URL is actually from a crate-internal path, serve it there instead
            return rustdoc_html_server_handler(req);
        } else {
            let path = req.url.path();
            let path = path.join("/");
            let conn = extension!(req, Pool);
            match File::from_path(&conn, &path) {
                Some(f) => return Ok(f.serve()),
                None => return Err(IronError::new(Nope::ResourceNotFound, status::NotFound)),
            }
        }
    } else if req.url.as_ref().path_segments().unwrap().last().map_or(false, |s| s.ends_with(".ico")) {
        // route .ico files into their dedicated handler so that docs.rs's favicon is always
        // displayed
        return super::ico_handler(req);
    }

    let router = extension!(req, Router);
    // this handler should never called without crate pattern
    let crate_name = cexpect!(router.find("crate"));
    let req_version = router.find("version");

    let conn = extension!(req, Pool);

    // it doesn't matter if the version that was given was exact or not, since we're redirecting
    // anyway
    let version = match match_version(&conn, &crate_name, req_version).into_option() {
        Some(v) => v,
        None => return Err(IronError::new(Nope::CrateNotFound, status::NotFound)),
    };

    // get target name and whether it has docs
    // FIXME: This is a bit inefficient but allowing us to use less code in general
    let (target_name, has_docs): (String, bool) = {
        let rows = ctry!(conn.query("SELECT target_name, rustdoc_status
                                     FROM releases
                                     INNER JOIN crates ON crates.id = releases.crate_id
                                     WHERE crates.name = $1 AND releases.version = $2",
                                    &[&crate_name, &version]));

        (rows.get(0).get(0), rows.get(0).get(1))
    };

    if has_docs {
        redirect_to_doc(req, &crate_name, &version, &target_name)
    } else {
        redirect_to_crate(req, &crate_name, &version)
    }
}

/// Serves documentation generated by rustdoc.
///
/// This includes all HTML files for an individual crate, as well as the `search-index.js`, which is
/// also crate-specific.
pub fn rustdoc_html_server_handler(req: &mut Request) -> IronResult<Response> {

    let router = extension!(req, Router);
    let name = router.find("crate").unwrap_or("").to_string();
    let url_version = router.find("version");
    let version; // pre-declaring it to enforce drop order relative to `req_path`
    let conn = extension!(req, Pool);

    let mut req_path = req.url.path();

    // remove name and version from path
    for _ in 0..2 {
        req_path.remove(0);
    }

    version = match match_version(&conn, &name, url_version) {
        MatchVersion::Exact(v) => v,
        MatchVersion::Semver(v) => {
            // to prevent cloudfront caching the wrong artifacts on URLs with loose semver
            // versions, redirect the browser to the returned version instead of loading it
            // immediately
            let url = ctry!(Url::parse(&format!("{}/{}/{}/{}",
                                                redirect_base(req),
                                                name,
                                                v,
                                                req_path.join("/"))[..]));
            return Ok(super::redirect(url));
        }
        MatchVersion::None => return Err(IronError::new(Nope::ResourceNotFound, status::NotFound)),
    };

    // docs have "rustdoc" prefix in database
    req_path.insert(0, "rustdoc");

    // add crate name and version
    req_path.insert(1, &name);
    req_path.insert(2, &version);

    let path = {
        let mut path = req_path.join("/");
        if path.ends_with('/') {
            req_path.pop(); // get rid of empty string
            path.push_str("index.html");
            req_path.push("index.html");
        }
        path
    };

    let file = match File::from_path(&conn, &path) {
        Some(f) => f,
        None => return Err(IronError::new(Nope::ResourceNotFound, status::NotFound)),
    };

    // serve file directly if it's not html
    if !path.ends_with(".html") {
        return Ok(file.serve());
    }

    let mut content = RustdocPage::default();

    let file_content = ctry!(String::from_utf8(file.0.content));

    let (head, body, mut body_class) = ctry!(utils::extract_head_and_body(&file_content));
    content.head = head;
    content.body = body;

    if body_class.is_empty() {
        body_class = "rustdoc container-rustdoc".to_string();
    } else {
        // rustdoc adds its own "rustdoc" class to the body
        body_class.push_str(" container-rustdoc");
    }
    content.body_class = body_class;

    content.full = file_content;
    let crate_details = cexpect!(CrateDetails::new(&conn, &name, &version));
    let (path, version) = if let Some(version) = latest_version(&crate_details.versions, &version) {
        req_path[2] = &version;
        (path_for_version(&req_path, &crate_details.target_name, &conn), version)
    } else {
        Default::default()
    };

    content.crate_details = Some(crate_details);

    Page::new(content)
        .set_true("show_package_navigation")
        .set_true("package_navigation_documentation_tab")
        .set_true("package_navigation_show_platforms_tab")
        .set_bool("is_latest_version", path.is_empty())
        .set("path_in_latest", &path)
        .set("latest_version", &version)
        .to_resp("rustdoc")
}

/// Checks whether the given path exists.
/// The crate's `target_name` is used to confirm whether a platform triple is part of the path.
///
/// Note that path is overloaded in this context to mean both the path of a URL
/// and the file path of a static file in the DB.
///
/// `req_path` is assumed to have the following format:
/// `rustdoc/crate/version[/platform]/module/[kind.name.html|index.html]`
///
/// Returns a path that can be appended to `/crate/version/` to create a complete URL.
fn path_for_version(req_path: &[&str], target_name: &str, conn: &Connection) -> String {
    // Simple case: page exists in the latest version, so just change the version number
    if File::from_path(&conn, &req_path.join("/")).is_some() {
        // NOTE: this adds 'index.html' if it wasn't there before
        return req_path[3..].join("/");
    }
    // this page doesn't exist in the latest version
    let search_item = if *req_path.last().unwrap() == "index.html" {
        // this is a module
        req_path[req_path.len() - 2]
    } else {
        // this is an item
        req_path.last().unwrap().split('.').nth(1)
            .expect("paths should be of the form <kind>.<name>.html")
    };
    // check if req_path[3] is the platform choice or the name of the crate
    let concat_path;
    let crate_root = if req_path[3] != target_name {
        concat_path = format!("{}/{}", req_path[3], req_path[4]);
        &concat_path
    } else {
        req_path[3]
    };
    format!("{}/?search={}", crate_root, search_item)
}

pub fn badge_handler(req: &mut Request) -> IronResult<Response> {
    use iron::headers::ContentType;
    use params::{Params, Value};
    use badge::{Badge, BadgeOptions};

    let version = {
        let params = ctry!(req.get_ref::<Params>());
        match params.find(&["version"]) {
            Some(&Value::String(ref version)) => version.clone(),
            _ => "*".to_owned(),
        }
    };

    let name = cexpect!(extension!(req, Router).find("crate"));
    let conn = extension!(req, Pool);

    let options = match match_version(&conn, &name, Some(&version)) {
        MatchVersion::Exact(version) => {
            let rows = ctry!(conn.query("SELECT rustdoc_status
                                         FROM releases
                                         INNER JOIN crates ON crates.id = releases.crate_id
                                         WHERE crates.name = $1 AND releases.version = $2",
                                        &[&name, &version]));
            if rows.len() > 0 && rows.get(0).get(0) {
                BadgeOptions {
                    subject: "docs".to_owned(),
                    status: version,
                    color: "#4d76ae".to_owned(),
                }
            } else {
                BadgeOptions {
                    subject: "docs".to_owned(),
                    status: version,
                    color: "#e05d44".to_owned(),
                }
            }
        }
        MatchVersion::Semver(version) => {
            let url = ctry!(Url::parse(&format!("{}/{}/badge.svg?version={}",
                                                redirect_base(req),
                                                name,
                                                version)[..]));

            return Ok(super::redirect(url));
        }
        MatchVersion::None => {
            BadgeOptions {
                subject: "docs".to_owned(),
                status: "no builds".to_owned(),
                color: "#e05d44".to_owned(),
            }
        }
    };

    let mut resp = Response::with((status::Ok, ctry!(Badge::new(options)).to_svg()));
    resp.headers.set(ContentType("image/svg+xml".parse().unwrap()));
    resp.headers.set(Expires(HttpDate(time::now())));
    resp.headers.set(CacheControl(vec![CacheDirective::NoCache,
                                       CacheDirective::NoStore,
                                       CacheDirective::MustRevalidate]));
    Ok(resp)
}

/// Serves shared web resources used by rustdoc-generated documentation.
///
/// This includes common `css` and `js` files that only change when the compiler is updated, but are
/// otherwise the same for all crates documented with that compiler. Those have a custom handler to
/// deduplicate them and save space.
pub struct SharedResourceHandler;

impl Handler for SharedResourceHandler {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        let path = req.url.path();
        let filename = path.last().unwrap();  // unwrap is fine: vector is non-empty
        let suffix = filename.split('.').last().unwrap();  // unwrap is fine: split always works
        if ["js", "css", "woff", "svg"].contains(&suffix) {
            let conn = extension!(req, Pool);

            if let Some(file) = File::from_path(conn, filename) {
                return Ok(file.serve());
            }
        }

        // Just always return a 404 here - the main handler will then try the other handlers
        Err(IronError::new(Nope::ResourceNotFound, status::NotFound))
    }
}
<|endoftext|>


<commit_before>use std::vec;

struct StorageByInts2<T> {
  data: ~[T],
  size_0: uint,
  size_1: uint,
}

impl <T:Clone> StorageByInts2<T> {

  pub fn from_fn(size_0: uint, size_1: uint,
                 f: |i0:uint, i1:uint| -> T) -> StorageByInts2<T> {
    let mut data = vec::with_capacity(size_0 * size_1);
    for i0 in range(0, size_0) {
      for i1 in range(0, size_1) {
        data.push(f(i0, i1));
      }
    }
    StorageByInts2 {
      data: data,
      size_0: size_0,
      size_1: size_1,
    }
  }

  #[inline]
  pub fn get(&self, i0: uint, i1: uint) -> T {
    self.data[i0 * self.size_1 + i1].clone()
  }

  #[inline]
  pub fn set(&mut self, i0: uint, i1: uint, val: T) {
    self.data[i0 * self.size_1 + i1] = val;
  }

}

struct StorageByInts3<T> {
  data: ~[T],
  size_0: uint,
  size_1: uint,
  size_2: uint,
}

impl <T:Clone> StorageByInts3<T> {

  pub fn from_fn(size_0: uint, size_1: uint, size_2: uint,
                 f: |i0:uint, i1:uint, i2:uint| -> T) -> StorageByInts3<T> {
    let mut data = vec::with_capacity(size_0 * size_1 * size_2);
    for i0 in range(0, size_0) {
      for i1 in range(0, size_1) {
        for i2 in range(0, size_2) {
          data.push(f(i0, i1, i2));
        }
      }
    }
    StorageByInts3 {
      data: data,
      size_0: size_0,
      size_1: size_1,
      size_2: size_2,
    }
  }

  #[inline]
  pub fn get(&self, i0: uint, i1: uint, i2: uint) -> T {
    self.data[(i0 * self.size_1 + i1)*self.size_2 + i2].clone()
  }
}

struct StorageByInts4<T> {
  data: ~[T],
  size_0: uint,
  size_1: uint,
  size_2: uint,
  size_3: uint,
}

impl <T:Clone> StorageByInts4<T> {

  pub fn from_elem(size_0: uint, size_1: uint, size_2: uint, size_3: uint, elem: T) -> StorageByInts4<T> {
    let sz = size_0 * size_1 * size_2 * size_3;
    let mut data = vec::with_capacity(sz);
    for i0 in range(0, size_0) {
      for i1 in range(0, size_1) {
        for i2 in range(0, size_2) {
          for i3 in range(0, size_3) {
            data.push(elem.clone());
          }
        }
      }
    }
    StorageByInts4 {
      data: data,
      size_0: size_0,
      size_1: size_1,
      size_2: size_2,
      size_3: size_3,
    }
  }

  pub fn from_fn(size_0: uint, size_1: uint, size_2: uint, size_3: uint,
                 f: |i0:uint, i1:uint, i2:uint, i3: uint| -> T) -> StorageByInts4<T> {
    let sz = size_0 * size_1 * size_2 * size_3;
    let mut data = vec::with_capacity(sz);
    for i0 in range(0, size_0) {
      for i1 in range(0, size_1) {
        for i2 in range(0, size_2) {
          for i3 in range(0, size_3) {
            data.push(f(i0, i1, i2, i3));
          }
        }
      }
    }
    StorageByInts4 {
      data: data,
      size_0: size_0,
      size_1: size_1,
      size_2: size_2,
      size_3: size_3,
    }
  }

  #[inline]
  pub fn get(&self, i0: uint, i1: uint, i2: uint, i3: uint) -> T {
    self.data[((i0 * self.size_1 + i1) * self.size_2 + i2) * self.size_3 + i3].clone()
  }
}

struct StorageByInts5<T> {
  data: ~[T],
  size_0: uint,
  size_1: uint,
  size_2: uint,
  size_3: uint,
  size_4: uint,
}

impl <T:Clone> StorageByInts5<T> {

  pub fn from_fn(size_0: uint, size_1: uint, size_2: uint, size_3: uint, size_4: uint,
                 f: |i0:uint, i1:uint, i2:uint, i3: uint, i4: uint| -> T) -> StorageByInts5<T> {
    let sz = size_0 * size_1 * size_2 * size_3 * size_4;
    let mut data = vec::with_capacity(sz);
    for i0 in range(0, size_0) {
      for i1 in range(0, size_1) {
        for i2 in range(0, size_2) {
          for i3 in range(0, size_3) {
            for i4 in range(0, size_4) {
              data.push(f(i0, i1, i2, i3, i4));
            }
          }
        }
      }
    }
    StorageByInts5 {
      data: data,
      size_0: size_0,
      size_1: size_1,
      size_2: size_2,
      size_3: size_3,
      size_4: size_4,
    }
  }

  #[inline]
  pub fn get(&self, i0: uint, i1: uint, i2: uint, i3: uint, i4: uint) -> T {
    self.data[(((i0 * self.size_1 + i1) * self.size_2 + i2) * self.size_3 + i3) * self.size_4 + i4].clone()
  }
}

<commit_msg>Make structs public and provide more efficient from_elem for StorageByInts4.<commit_after>use std::vec;

pub struct StorageByInts2<T> {
  data: ~[T],
  size_0: uint,
  size_1: uint,
}

impl <T:Clone> StorageByInts2<T> {

  pub fn from_fn(size_0: uint, size_1: uint,
                 f: |i0:uint, i1:uint| -> T) -> StorageByInts2<T> {
    let mut data = vec::with_capacity(size_0 * size_1);
    for i0 in range(0, size_0) {
      for i1 in range(0, size_1) {
        data.push(f(i0, i1));
      }
    }
    StorageByInts2 {
      data: data,
      size_0: size_0,
      size_1: size_1,
    }
  }

  #[inline]
  pub fn get(&self, i0: uint, i1: uint) -> T {
    self.data[i0 * self.size_1 + i1].clone()
  }

  #[inline]
  pub fn set(&mut self, i0: uint, i1: uint, val: T) {
    self.data[i0 * self.size_1 + i1] = val;
  }

}

pub struct StorageByInts3<T> {
  data: ~[T],
  size_0: uint,
  size_1: uint,
  size_2: uint,
}

impl <T:Clone> StorageByInts3<T> {

  pub fn from_fn(size_0: uint, size_1: uint, size_2: uint,
                 f: |i0:uint, i1:uint, i2:uint| -> T) -> StorageByInts3<T> {
    let mut data = vec::with_capacity(size_0 * size_1 * size_2);
    for i0 in range(0, size_0) {
      for i1 in range(0, size_1) {
        for i2 in range(0, size_2) {
          data.push(f(i0, i1, i2));
        }
      }
    }
    StorageByInts3 {
      data: data,
      size_0: size_0,
      size_1: size_1,
      size_2: size_2,
    }
  }

  #[inline]
  pub fn get(&self, i0: uint, i1: uint, i2: uint) -> T {
    self.data[(i0 * self.size_1 + i1)*self.size_2 + i2].clone()
  }
}

pub struct StorageByInts4<T> {
  data: ~[T],
  size_0: uint,
  size_1: uint,
  size_2: uint,
  size_3: uint,
}

impl <T:Clone> StorageByInts4<T> {

  pub fn from_elem(size_0: uint, size_1: uint, size_2: uint, size_3: uint, elem: T) -> StorageByInts4<T> {
    let sz = size_0 * size_1 * size_2 * size_3;
    let data = vec::from_elem(sz, elem);
    StorageByInts4 {
      data: data,
      size_0: size_0,
      size_1: size_1,
      size_2: size_2,
      size_3: size_3,
    }
  }

  pub fn from_fn(size_0: uint, size_1: uint, size_2: uint, size_3: uint,
                 f: |i0:uint, i1:uint, i2:uint, i3: uint| -> T) -> StorageByInts4<T> {
    let sz = size_0 * size_1 * size_2 * size_3;
    let mut data = vec::with_capacity(sz);
    for i0 in range(0, size_0) {
      for i1 in range(0, size_1) {
        for i2 in range(0, size_2) {
          for i3 in range(0, size_3) {
            data.push(f(i0, i1, i2, i3));
          }
        }
      }
    }
    StorageByInts4 {
      data: data,
      size_0: size_0,
      size_1: size_1,
      size_2: size_2,
      size_3: size_3,
    }
  }

  #[inline]
  pub fn get(&self, i0: uint, i1: uint, i2: uint, i3: uint) -> T {
    self.data[((i0 * self.size_1 + i1) * self.size_2 + i2) * self.size_3 + i3].clone()
  }
}

pub struct StorageByInts5<T> {
  data: ~[T],
  size_0: uint,
  size_1: uint,
  size_2: uint,
  size_3: uint,
  size_4: uint,
}

impl <T:Clone> StorageByInts5<T> {

  pub fn from_fn(size_0: uint, size_1: uint, size_2: uint, size_3: uint, size_4: uint,
                 f: |i0:uint, i1:uint, i2:uint, i3: uint, i4: uint| -> T) -> StorageByInts5<T> {
    let sz = size_0 * size_1 * size_2 * size_3 * size_4;
    let mut data = vec::with_capacity(sz);
    for i0 in range(0, size_0) {
      for i1 in range(0, size_1) {
        for i2 in range(0, size_2) {
          for i3 in range(0, size_3) {
            for i4 in range(0, size_4) {
              data.push(f(i0, i1, i2, i3, i4));
            }
          }
        }
      }
    }
    StorageByInts5 {
      data: data,
      size_0: size_0,
      size_1: size_1,
      size_2: size_2,
      size_3: size_3,
      size_4: size_4,
    }
  }

  #[inline]
  pub fn get(&self, i0: uint, i1: uint, i2: uint, i3: uint, i4: uint) -> T {
    self.data[(((i0 * self.size_1 + i1) * self.size_2 + i2) * self.size_3 + i3) * self.size_4 + i4].clone()
  }
}

<|endoftext|>


<commit_before>#[cfg(feature = "libc")]
pub extern crate libc;

#[macro_use]
mod macros;

#[macro_use]
pub mod coreopts;

pub mod panic;

#[cfg(feature = "fs")]
pub mod fs;
#[cfg(feature = "utf8")]
pub mod utf8;
#[cfg(feature = "encoding")]
pub mod encoding;
#[cfg(feature = "parse_time")]
pub mod parse_time;
#[cfg(feature = "mode")]
pub mod mode;

#[cfg(all(unix, not(target_os = "fuchsia"), feature = "utmpx"))]
pub mod utmpx;
#[cfg(all(unix, feature = "utsname"))]
pub mod utsname;
#[cfg(all(unix, feature = "entries"))]
pub mod entries;
#[cfg(all(unix, feature = "process"))]
pub mod process;
#[cfg(all(unix, not(target_os = "fuchsia"), feature = "signals"))]
pub mod signals;

#[cfg(all(windows, feature = "wide"))]
pub mod wide;
<commit_msg>chmod, install, uucore: fix build on Windows<commit_after>#[cfg(feature = "libc")]
pub extern crate libc;

#[macro_use]
mod macros;

#[macro_use]
pub mod coreopts;

pub mod panic;

#[cfg(feature = "fs")]
pub mod fs;
#[cfg(feature = "utf8")]
pub mod utf8;
#[cfg(feature = "encoding")]
pub mod encoding;
#[cfg(feature = "parse_time")]
pub mod parse_time;

#[cfg(all(not(windows), feature = "mode"))]
pub mod mode;
#[cfg(all(unix, not(target_os = "fuchsia"), feature = "utmpx"))]
pub mod utmpx;
#[cfg(all(unix, feature = "utsname"))]
pub mod utsname;
#[cfg(all(unix, feature = "entries"))]
pub mod entries;
#[cfg(all(unix, feature = "process"))]
pub mod process;
#[cfg(all(unix, not(target_os = "fuchsia"), feature = "signals"))]
pub mod signals;

#[cfg(all(windows, feature = "wide"))]
pub mod wide;
<|endoftext|>


<commit_before>// http://rosettacode.org/wiki/Hamming_numbers
// NOTE: If you change this file please make sure you run main().  It has a larger test that can
// trip up on large floating point values, but is too expensive to run every time we run the tests.
extern crate num;
use num::bigint::{BigUint, ToBigUint};
use std::cmp::min;
use std::num::{One, one};
use std::collections::{RingBuf, Deque};

// needed because hamming_numbers_alt uses this as a library
#[allow(dead_code)]
#[cfg(not(test))]
fn main() {
    static HAMMING_1_MILLION: &'static str =
"519312780448388736089589843750000000000000000000000000000000000000000000000000000000";
    // capacity of the queue currently needs to be a power of 2 because of a bug with RingBuf
    let hamming : Hamming<BigUint> = Hamming::new(128);

    for (idx, h) in hamming.enumerate().take(1_000_000) {
        match idx + 1 {
            1...20 => print!("{} ", h.to_biguint().unwrap()),
            i @ 1691 => println!("\n{}th number: {}", i, h.to_biguint().unwrap()),
            i @ 1000000 => {
                let n = h.to_biguint().unwrap();
                println!("\n{}th number: {}", i, n);
                assert_eq!(n, from_str(HAMMING_1_MILLION).unwrap())
            },
            _ =>  continue
        }
    }
}

//representing a Hamming number as a BigUint
impl HammingNumber for BigUint {
    // returns the multipliers 2, 3 and 5 in the representation for the HammingNumber
    fn multipliers()-> (BigUint, BigUint, BigUint) {
        (2u.to_biguint().unwrap(),
        3u.to_biguint().unwrap(),
        5u.to_biguint().unwrap())
    }
}

/// representation of a Hamming number
/// allows to abstract on how the hamming number is stored
/// i.e. as BigUint directly or just as the powers of 2, 3 and 5 used to build it
pub trait HammingNumber : Eq + Ord + ToBigUint + Mul<Self, Self> + One {
    fn multipliers() -> (Self, Self, Self);
}

/// Hamming numbers are multiples of 2, 3 or 5.
///
/// We keep them on three queues and extract the lowest (leftmost) value from
/// the three queues at each iteration.
pub struct Hamming<T> {
    // Using a RingBuf as a queue, push to the back, pop from the front
    q2: RingBuf<T>,
    q3: RingBuf<T>,
    q5: RingBuf<T>
}

impl<T: HammingNumber> Hamming<T> {
    /// Static constructor method
    /// `n` initializes the capacity of the queues
    pub fn new(n: uint) -> Hamming<T> {
        let mut h = Hamming {
            q2: RingBuf::with_capacity(n),
            q3: RingBuf::with_capacity(n),
            q5: RingBuf::with_capacity(n)
        };

        h.q2.push(one());
        h.q3.push(one());
        h.q5.push(one());

        h
    }

    /// Pushes the next multiple of `n` (x2, x3, x5) to the queues
    pub fn enqueue(&mut self, n: &T) {
        let (two, three, five) = HammingNumber::multipliers();
        self.q2.push(*n * two);
        self.q3.push(*n * three);
        self.q5.push(*n * five);
    }
}

// Implements the `Iterator` trait, so we can generate Hamming numbers lazily
impl<T: HammingNumber> Iterator<T> for Hamming<T> {
    // The core of the work is done in the `next` method.
    // We check which of the 3 queues has the lowest candidate and extract it
    // as the next Hamming number.
    fn next(&mut self) -> Option<T> {
        // Return `pop_targets` so the borrow from `front()` will be finished
        let (two, three, five) = match (self.q2.front(),
                                        self.q3.front(),
                                        self.q5.front()) {
            (Some(head2), Some(head3), Some(head5)) => {
                let n = min(head2, min(head3, head5));
                (head2 == n, head3 == n, head5 == n)
            },
            _ => unreachable!()
        };

        let h2 = if two { self.q2.pop_front() } else { None };
        let h3 = if three { self.q3.pop_front() } else { None };
        let h5 = if five { self.q5.pop_front() } else { None };

        match h2.or(h3).or(h5) {
            Some(n) => {
                self.enqueue(&n);
                Some(n)
            }
            None => unreachable!()
        }
    }
}

#[test]
fn create() {
    let mut h = Hamming::<BigUint>::new(5);
    h.q2.push(one::<BigUint>());
    h.q2.push(one::<BigUint>() * 3u.to_biguint().unwrap());

    assert_eq!(h.q2.pop_front().unwrap(), one::<BigUint>());
}

#[test]
fn try_enqueue() {
    let mut h = Hamming::<BigUint>::new(5);
    let (two, three, five) = HammingNumber::multipliers();
    h.enqueue(&one::<BigUint>());
    h.enqueue(&(&one::<BigUint>() * two));

    assert!(h.q2.pop_front().unwrap() == one::<BigUint>());
    assert!(h.q3.pop_front().unwrap() == one::<BigUint>());
    assert!(h.q5.pop_front().unwrap() == one::<BigUint>());
    assert!(h.q2.pop_front().unwrap() == one::<BigUint>() * two);
    assert!(h.q3.pop_front().unwrap() == one::<BigUint>() * three);
    assert!(h.q5.pop_front().unwrap() == one::<BigUint>() * five);
 }

#[test]
fn hamming_iter() {
    let mut hamming = Hamming::<BigUint>::new(20);
    assert!(hamming.nth(19).unwrap().to_biguint() == 36u.to_biguint());
}
<commit_msg>Revert "Removing slow test from Hamming numbers (still exists if you run main())."<commit_after>// http://rosettacode.org/wiki/Hamming_numbers
// NOTE: If you change this file please make sure you run main().  It has a larger test that can
// trip up on large floating point values, but is too expensive to run every time we run the tests.
extern crate num;
use num::bigint::{BigUint, ToBigUint};
use std::cmp::min;
use std::num::{One, one};
use std::collections::{RingBuf, Deque};

// needed because hamming_numbers_alt uses this as a library
#[allow(dead_code)]
#[cfg(not(test))]
fn main() {
    // capacity of the queue currently needs to be a power of 2 because of a bug with RingBuf
    let hamming : Hamming<BigUint> = Hamming::new(128);

    for (idx, h) in hamming.enumerate().take(1_000_000) {
        match idx + 1 {
            1...20 => print!("{} ", h.to_biguint().unwrap()),
            i @ 1691 | i @ 1000000 => println!("\n{}th number: {}", i, h.to_biguint().unwrap()),
            _ =>  continue
        }
    }
}
//representing a Hamming number as a BigUint
impl HammingNumber for BigUint {
    // returns the multipliers 2, 3 and 5 in the representation for the HammingNumber
    fn multipliers()-> (BigUint, BigUint, BigUint) {
        (2u.to_biguint().unwrap(),
        3u.to_biguint().unwrap(),
        5u.to_biguint().unwrap())
    }
}

/// representation of a Hamming number
/// allows to abstract on how the hamming number is stored
/// i.e. as BigUint directly or just as the powers of 2, 3 and 5 used to build it
pub trait HammingNumber : Eq + Ord + ToBigUint + Mul<Self, Self> + One {
    fn multipliers() -> (Self, Self, Self);
}

/// Hamming numbers are multiples of 2, 3 or 5.
///
/// We keep them on three queues and extract the lowest (leftmost) value from
/// the three queues at each iteration.
pub struct Hamming<T> {
    // Using a RingBuf as a queue, push to the back, pop from the front
    q2: RingBuf<T>,
    q3: RingBuf<T>,
    q5: RingBuf<T>
}

impl<T: HammingNumber> Hamming<T> {
    /// Static constructor method
    /// `n` initializes the capacity of the queues
    pub fn new(n: uint) -> Hamming<T> {
        let mut h = Hamming {
            q2: RingBuf::with_capacity(n),
            q3: RingBuf::with_capacity(n),
            q5: RingBuf::with_capacity(n)
        };

        h.q2.push(one());
        h.q3.push(one());
        h.q5.push(one());

        h
    }

    /// Pushes the next multiple of `n` (x2, x3, x5) to the queues
    pub fn enqueue(&mut self, n: &T) {
        let (two, three, five) = HammingNumber::multipliers();
        self.q2.push(*n * two);
        self.q3.push(*n * three);
        self.q5.push(*n * five);
    }
}

// Implements the `Iterator` trait, so we can generate Hamming numbers lazily
impl<T: HammingNumber> Iterator<T> for Hamming<T> {
    // The core of the work is done in the `next` method.
    // We check which of the 3 queues has the lowest candidate and extract it
    // as the next Hamming number.
    fn next(&mut self) -> Option<T> {
        // Return `pop_targets` so the borrow from `front()` will be finished
        let (two, three, five) = match (self.q2.front(),
                                        self.q3.front(),
                                        self.q5.front()) {
            (Some(head2), Some(head3), Some(head5)) => {
                let n = min(head2, min(head3, head5));
                (head2 == n, head3 == n, head5 == n)
            },
            _ => unreachable!()
        };

        let h2 = if two { self.q2.pop_front() } else { None };
        let h3 = if three { self.q3.pop_front() } else { None };
        let h5 = if five { self.q5.pop_front() } else { None };

        match h2.or(h3).or(h5) {
            Some(n) => {
                self.enqueue(&n);
                Some(n)
            }
            None => unreachable!()
        }
    }
}

#[test]
fn create() {
    let mut h = Hamming::<BigUint>::new(5);
    h.q2.push(one::<BigUint>());
    h.q2.push(one::<BigUint>() * 3u.to_biguint().unwrap());

    assert_eq!(h.q2.pop_front().unwrap(), one::<BigUint>());
}

#[test]
fn try_enqueue() {
    let mut h = Hamming::<BigUint>::new(5);
    let (two, three, five) = HammingNumber::multipliers();
    h.enqueue(&one::<BigUint>());
    h.enqueue(&(&one::<BigUint>() * two));

    assert!(h.q2.pop_front().unwrap() == one::<BigUint>());
    assert!(h.q3.pop_front().unwrap() == one::<BigUint>());
    assert!(h.q5.pop_front().unwrap() == one::<BigUint>());
    assert!(h.q2.pop_front().unwrap() == one::<BigUint>() * two);
    assert!(h.q3.pop_front().unwrap() == one::<BigUint>() * three);
    assert!(h.q5.pop_front().unwrap() == one::<BigUint>() * five);
 }

#[test]
fn hamming_iter() {
    let mut hamming = Hamming::<BigUint>::new(20);
    assert!(hamming.nth(19).unwrap().to_biguint() == 36u.to_biguint());
}

#[test]
fn hamming_iter_1million() {
    let mut hamming = Hamming::<BigUint>::new(128);
    // one-million-th hamming number has index 999_999 because indexes are zero-based
    assert_eq!(hamming.nth(999_999).unwrap().to_biguint(),
        from_str(
        "519312780448388736089589843750000000000000000000000000000000000000000000000000000000")
        );
}
<|endoftext|>


<commit_before>use crate::utils::{
    in_macro, is_type_diagnostic_item, match_qpath, paths, return_ty, snippet, span_lint_and_then,
    visitors::find_all_ret_expressions,
};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::intravisit::FnKind;
use rustc_hir::*;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::subst::GenericArgKind;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::Span;

declare_clippy_lint! {
    /// **What it does:** Checks for private functions that only return `Ok` or `Some`.
    ///
    /// **Why is this bad?** It is not meaningful to wrap values when no `None` or `Err` is returned.
    ///
    /// **Known problems:** Since this lint changes function type signature, you may need to
    /// adjust some code at callee side.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// fn get_cool_number(a: bool, b: bool) -> Option<i32> {
    ///     if a && b {
    ///         return Some(50);
    ///     }
    ///     if a {
    ///         Some(0)
    ///     } else {
    ///         Some(10)
    ///     }
    /// }
    /// ```
    /// Use instead:
    /// ```rust
    /// fn get_cool_number(a: bool, b: bool) -> i32 {
    ///     if a && b {
    ///         return 50;
    ///     }
    ///     if a {
    ///         0
    ///     } else {
    ///         10
    ///     }
    /// }
    /// ```
    pub UNNECESSARY_WRAP,
    complexity,
    "functions that only return `Ok` or `Some`"
}

declare_lint_pass!(UnnecessaryWrap => [UNNECESSARY_WRAP]);

impl<'tcx> LateLintPass<'tcx> for UnnecessaryWrap {
    fn check_fn(
        &mut self,
        cx: &LateContext<'tcx>,
        fn_kind: FnKind<'tcx>,
        fn_decl: &FnDecl<'tcx>,
        body: &Body<'tcx>,
        span: Span,
        hir_id: HirId,
    ) {
        match fn_kind {
            FnKind::ItemFn(.., visibility, _) | FnKind::Method(.., Some(visibility), _) => {
                if visibility.node.is_pub() {
                    return;
                }
            },
            FnKind::Closure(..) => return,
            _ => (),
        }

        let (return_type, path) = if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(option_type)) {
            ("Option", &paths::OPTION_SOME)
        } else if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(result_type)) {
            ("Result", &paths::RESULT_OK)
        } else {
            return;
        };

        let mut suggs = Vec::new();
        let can_sugg = find_all_ret_expressions(cx, &body.value, |ret_expr| {
            if_chain! {
                if !in_macro(ret_expr.span);
                if let ExprKind::Call(ref func, ref args) = ret_expr.kind;
                if let ExprKind::Path(ref qpath) = func.kind;
                if match_qpath(qpath, path);
                if args.len() == 1;
                then {
                    suggs.push((ret_expr.span, snippet(cx, args[0].span.source_callsite(), "..").to_string()));
                    true
                } else {
                    false
                }
            }
        });

        if can_sugg {
            span_lint_and_then(
                cx,
                UNNECESSARY_WRAP,
                span,
                format!(
                    "this function's return value is unnecessarily wrapped by `{}`",
                    return_type
                )
                .as_str(),
                |diag| {
                    let inner_ty = return_ty(cx, hir_id)
                        .walk()
                        .skip(1) // skip `std::option::Option` or `std::result::Result`
                        .take(1) // take the first outermost inner type
                        .filter_map(|inner| match inner.unpack() {
                            GenericArgKind::Type(inner_ty) => Some(inner_ty.to_string()),
                            _ => None,
                        });
                    inner_ty.for_each(|inner_ty| {
                        diag.span_suggestion(
                            fn_decl.output.span(),
                            format!("remove `{}` from the return type...", return_type).as_str(),
                            inner_ty,
                            Applicability::MachineApplicable,
                        );
                    });
                    diag.multipart_suggestion(
                        "...and change the returning expressions",
                        suggs,
                        Applicability::MachineApplicable,
                    );
                },
            );
        }
    }
}
<commit_msg>Skip function with no exprs contained<commit_after>use crate::utils::{
    in_macro, is_type_diagnostic_item, match_qpath, paths, return_ty, snippet, span_lint_and_then,
    visitors::find_all_ret_expressions,
};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::intravisit::FnKind;
use rustc_hir::*;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::subst::GenericArgKind;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::Span;

declare_clippy_lint! {
    /// **What it does:** Checks for private functions that only return `Ok` or `Some`.
    ///
    /// **Why is this bad?** It is not meaningful to wrap values when no `None` or `Err` is returned.
    ///
    /// **Known problems:** Since this lint changes function type signature, you may need to
    /// adjust some code at callee side.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// fn get_cool_number(a: bool, b: bool) -> Option<i32> {
    ///     if a && b {
    ///         return Some(50);
    ///     }
    ///     if a {
    ///         Some(0)
    ///     } else {
    ///         Some(10)
    ///     }
    /// }
    /// ```
    /// Use instead:
    /// ```rust
    /// fn get_cool_number(a: bool, b: bool) -> i32 {
    ///     if a && b {
    ///         return 50;
    ///     }
    ///     if a {
    ///         0
    ///     } else {
    ///         10
    ///     }
    /// }
    /// ```
    pub UNNECESSARY_WRAP,
    complexity,
    "functions that only return `Ok` or `Some`"
}

declare_lint_pass!(UnnecessaryWrap => [UNNECESSARY_WRAP]);

impl<'tcx> LateLintPass<'tcx> for UnnecessaryWrap {
    fn check_fn(
        &mut self,
        cx: &LateContext<'tcx>,
        fn_kind: FnKind<'tcx>,
        fn_decl: &FnDecl<'tcx>,
        body: &Body<'tcx>,
        span: Span,
        hir_id: HirId,
    ) {
        match fn_kind {
            FnKind::ItemFn(.., visibility, _) | FnKind::Method(.., Some(visibility), _) => {
                if visibility.node.is_pub() {
                    return;
                }
            },
            FnKind::Closure(..) => return,
            _ => (),
        }

        let (return_type, path) = if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(option_type)) {
            ("Option", &paths::OPTION_SOME)
        } else if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(result_type)) {
            ("Result", &paths::RESULT_OK)
        } else {
            return;
        };

        let mut suggs = Vec::new();
        let can_sugg = find_all_ret_expressions(cx, &body.value, |ret_expr| {
            if_chain! {
                if !in_macro(ret_expr.span);
                if let ExprKind::Call(ref func, ref args) = ret_expr.kind;
                if let ExprKind::Path(ref qpath) = func.kind;
                if match_qpath(qpath, path);
                if args.len() == 1;
                then {
                    suggs.push((ret_expr.span, snippet(cx, args[0].span.source_callsite(), "..").to_string()));
                    true
                } else {
                    false
                }
            }
        });

        if can_sugg && !suggs.is_empty() {
            span_lint_and_then(
                cx,
                UNNECESSARY_WRAP,
                span,
                format!(
                    "this function's return value is unnecessarily wrapped by `{}`",
                    return_type
                )
                .as_str(),
                |diag| {
                    let inner_ty = return_ty(cx, hir_id)
                        .walk()
                        .skip(1) // skip `std::option::Option` or `std::result::Result`
                        .take(1) // take the first outermost inner type
                        .filter_map(|inner| match inner.unpack() {
                            GenericArgKind::Type(inner_ty) => Some(inner_ty.to_string()),
                            _ => None,
                        });
                    inner_ty.for_each(|inner_ty| {
                        diag.span_suggestion(
                            fn_decl.output.span(),
                            format!("remove `{}` from the return type...", return_type).as_str(),
                            inner_ty,
                            Applicability::MachineApplicable,
                        );
                    });
                    diag.multipart_suggestion(
                        "...and change the returning expressions",
                        suggs,
                        Applicability::MachineApplicable,
                    );
                },
            );
        }
    }
}
<|endoftext|>


<commit_before>use lists::{filter, new_list};

mod lists {
  use std::fmt;
  use lists::List::{Cons, Nil};
  use std::sync::Arc;

  #[derive(PartialEq, Clone)]
  pub enum List<T> {
    Cons(T, Arc<List<T>>),
    Nil
  }

  impl<T> fmt::Display for List<T> where T : fmt::Display {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
      match *self {
        Cons(ref head, ref tail) =>
          {
            write!(f, "{head} :: ", head = head);
             write!(f, "{tail} ", tail = tail)
          }
        Nil => write!(f, "Nil")
      }
    }
  }

  #[allow(dead_code)]
  pub fn flat_map<T, U>(list: &List<T>, f: &Fn(T) -> List<U>) -> List<U> where T: Copy, T: Sized, T: Copy, T: PartialEq, U: Copy, U: Sized, U: PartialEq {
    match *list {
      Cons(ref head, ref tail) => concat(&f(*head), flat_map(tail, f)),
      Nil => Nil
    }
  }

  #[allow(dead_code)]
  pub fn filter<T>(list: &List<T>, f: &Fn(T) -> bool) -> List<T> where T : Copy {
    fold_right(list, Nil, &|x, y| if f(x) { Cons(x, Arc::new(filter(&y, f))) } else { filter(&y, f) })
  }

  #[allow(dead_code)]
  pub fn concat<T>(list: &List<T>, b: List<T>) -> List<T> where T: Copy, T: Sized {
    fold_right(list, b, &|x, y| Cons(x, Arc::new(y)))
  }

  #[allow(dead_code)]
  pub fn fold_right<T, U>(list: &List<T>, result: U, f: &Fn(T, U) -> U) -> U where T: Copy, T: Sized {
    match *list {
      Cons(ref head, ref tail) =>
        f(*head, fold_right(tail, result, f)),
      Nil => result
    }
  }

  #[allow(dead_code)]
  pub fn fold_left<T, U>(list: &List<T>, result: U, f: &Fn(U, T) -> U) -> U where T: Copy, T: Sized {
    match *list {
      Cons(ref head, ref tail) => fold_left(tail, f(result, *head), f),
      Nil => result
    }
  }

  #[allow(dead_code)]
  pub fn map<T, U>(list: &List<T>, f: &Fn(T) -> U) -> List<U> where T: Copy , U: Copy {
    fold_right(list, Nil, &|x, y| Cons(f(x), Arc::new(y)))
  }

  #[allow(dead_code)]
  pub fn new_list<T>(args: Vec<T>) -> List<T> where T: Copy {
    let mut vec = args;
    let mut x: List<T> = Nil;
    while vec.len() > 0 {
      match vec.pop() {
        Some(e) => x = Cons(e, Arc::new(x)),
        None => {}
      }
    }
    x
  }
}

fn main() {
  let list = new_list(vec![1, 2, 3, 4, 5]);
  println!("{list}", list = filter(&list, &|x| x < 4));
}
<commit_msg>Re-format<commit_after>use lists::{filter, new_list};

mod lists {
    use std::fmt;
    use lists::List::{Cons, Nil};
    use std::sync::Arc;

    #[derive(PartialEq, Clone)]
    pub enum List<T> {
        Cons(T, Arc<List<T>>),
        Nil
    }

    impl<T> fmt::Display for List<T> where T : fmt::Display {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            match *self {
                Cons(ref head, ref tail) =>
                {
                    write!(f, "{head} :: ", head = head);
                    write!(f, "{tail} ", tail = tail)
                }
                Nil => write!(f, "Nil")
            }
        }
    }

    #[allow(dead_code)]
    pub fn flat_map<T, U>(list: &List<T>, f: &Fn(T) -> List<U>) -> List<U> where T: Copy, T: Sized, T: Copy, T: PartialEq, U: Copy, U: Sized, U: PartialEq {
        match *list {
            Cons(ref head, ref tail) => concat(&f(*head), flat_map(tail, f)),
            Nil => Nil
        }
    }

    #[allow(dead_code)]
    pub fn filter<T>(list: &List<T>, f: &Fn(T) -> bool) -> List<T> where T : Copy {
        fold_right(list, Nil, &|x, y| if f(x) { Cons(x, Arc::new(filter(&y, f))) } else { filter(&y, f) })
    }

    #[allow(dead_code)]
    pub fn concat<T>(list: &List<T>, b: List<T>) -> List<T> where T: Copy, T: Sized {
        fold_right(list, b, &|x, y| Cons(x, Arc::new(y)))
    }

    #[allow(dead_code)]
    pub fn fold_right<T, U>(list: &List<T>, result: U, f: &Fn(T, U) -> U) -> U where T: Copy, T: Sized {
        match *list {
            Cons(ref head, ref tail) =>
                f(*head, fold_right(tail, result, f)),
            Nil => result
        }
    }

    #[allow(dead_code)]
    pub fn fold_left<T, U>(list: &List<T>, result: U, f: &Fn(U, T) -> U) -> U where T: Copy, T: Sized {
        match *list {
            Cons(ref head, ref tail) => fold_left(tail, f(result, *head), f),
            Nil => result
        }
    }

    #[allow(dead_code)]
    pub fn map<T, U>(list: &List<T>, f: &Fn(T) -> U) -> List<U> where T: Copy , U: Copy {
        fold_right(list, Nil, &|x, y| Cons(f(x), Arc::new(y)))
    }

    #[allow(dead_code)]
    pub fn new_list<T>(args: Vec<T>) -> List<T> where T: Copy {
        let mut vec = args;
        let mut x: List<T> = Nil;
        while vec.len() > 0 {
            match vec.pop() {
                Some(e) => x = Cons(e, Arc::new(x)),
                None => {}
            }
        }
        x
    }
}

fn main() {
    let list = new_list(vec![1, 2, 3, 4, 5]);
    println!("{list}", list = filter(&list, &|x| x < 4));
}
<|endoftext|>


<commit_before>#[cfg(feature="trace_log")] extern crate env_logger;

extern crate radeco_lib;
extern crate r2pipe;
extern crate r2api;
extern crate petgraph;

mod cli;

use std::env;
use std::fs::{self, File};
use std::io::Write;
use std::path::PathBuf;
use std::process;

use radeco_lib::analysis::cse::cse::CSE;
use radeco_lib::analysis::sccp;
//use radeco_lib::analysis::valueset::analyzer_wysinwyx::FnAnalyzer;
//use radeco_lib::analysis::valueset::mem_structs::{A_Loc,AbstractAddress};
use radeco_lib::analysis::interproc::fixcall::CallFixer;
use radeco_lib::frontend::radeco_containers::ProjectLoader;
use radeco_lib::middle::{dce, dot};
use radeco_lib::middle::ir_writer;
use radeco_lib::middle::ir_reader::parse_il;
use radeco_lib::middle::ssa::verifier;
use radeco_lib::backend::lang_c::{c_simple_ast, c_simple_ast_builder};

//use radeco_lib::analysis::mark_refs;

const USAGE: &'static str = "
Usage: minidec [-f <names>...] <target>

Options:
    -f, --functions  Analayze only some functions
";

fn main() {
    #[cfg(feature="trace_log")] env_logger::init();

    let requested_functions = cli::init_for_args(USAGE);

    let proj_name = env::args().nth(env::args().len() - 1).unwrap();
    let mut rproj = {
        ProjectLoader::new().path(&proj_name).load()
    };
    let regfile = rproj.regfile().clone();
    for mut xy in rproj.iter_mut() {
        let rmod = &mut xy.module;
        let mut dir = PathBuf::from(".");
        dir.push(format!("{}_out", proj_name));
        dir.push(format!("{}_out", rmod.name()));
        fs::create_dir_all(&dir).expect("Failed to create directory");

        // Reduce the complexity of rmod.functions to just a vec of (u64,&String)
        // for easier extraction and matching

        // Analyze preserved for all functions.
        {
            println!("[*] Fixing Callee Information");
            let bp_name = regfile.get_name_by_alias(&"BP".to_string());
            let bp_name = bp_name.map(|s| s.to_owned());
            let sp_name = regfile.get_name_by_alias(&"SP".to_string());
            let sp_name = sp_name.map(|s| s.to_owned());
            let mut callfixer = CallFixer::new(rmod, bp_name, sp_name);
            callfixer.rounded_analysis();
        }

        // Fix call sites
        radeco_lib::analysis::functions::fix_ssa_opcalls::go(rmod);

        // Infer calling conventions
        radeco_lib::analysis::functions::infer_regusage::run(rmod, &*regfile);

        // Filter the data if the user provided some args to be matched upon
        let matched_func_addrs = if requested_functions.len() != 0 {

            //XXX Impl in more efficient way
            let mut matched_func_vec: Vec<(u64, &str)> =
                rmod.iter().map(|_f| {
                    let f = _f.function.1;
                    (f.offset.clone(), &*f.name)
                }).collect();

            let all_func_names: Vec<(&str)> =
                matched_func_vec.iter().map(|&(_, name)| name).collect();
            matched_func_vec = filter_with(&matched_func_vec,
                                           &requested_functions.iter().map(|s| &s[..]).collect::<Vec<_>>());
            cli::print_match_summary(&matched_func_vec,
                                     &requested_functions.iter().map(|s| &s[..]).collect::<Vec<_>>(),
                                     &all_func_names);
            matched_func_vec.into_iter().map(|(addr, _)| addr).collect::<Vec<_>>()
        } else {
            Vec::new()
        };

        // Main file to contain IRs of all rfns
        let mut ffm = {
            let mut fname = PathBuf::from(&dir);
            fname.push("main");
            File::create(&fname).expect("Unable to create file")
        };

        for addr in matched_func_addrs {

            let ref mut rfn = rmod.functions.get_mut(&addr).unwrap();

            println!("[+] Analyzing: {} @ {:#x}", rfn.name, addr);
            {
                println!("  [*] Eliminating Dead Code");
                dce::collect(rfn.ssa_mut());
            }
            let mut ssa = {
                // Constant Propagation (sccp)
                println!("  [*] Propagating Constants");
                let mut analyzer = sccp::Analyzer::new(rfn.ssa_mut());
                analyzer.analyze();
                analyzer.emit_ssa()
            };
            {
                println!("  [*] Eliminating More DeadCode");
                dce::collect(&mut ssa);
            }
            *rfn.ssa_mut() = ssa;
            {
                // Common SubExpression Elimination (cse)
                println!("  [*] Eliminating Common SubExpressions");
                let mut cse = CSE::new(rfn.ssa_mut());
                cse.run();
            }
            {
                // Verify SSA
                println!("  [*] Verifying SSA's Validity");
                match verifier::verify(rfn.ssa()) {
                    Err(e) => {
                        println!("  [*] Found Error: {}", e);
                        process::exit(255);
                    }
                    Ok(_) => {  }
                }
            }
            {
                // TODO
                // // Building memory SSA.
                // let _memory_ssa = {
                //     // Generate MemorySSA
                //     println!("  [*] Generating Memory SSA");
                //     let mut mssa = MemorySSA::new(rfn.ssa());
                //     mssa.gather_variables(rfn.datarefs(), &rfn.locals(),
                //                           &rfn.call_refs(&rmod.callgraph));
                //     mssa.run();
                //     mssa
                // };
            }
            //if false {
            //    if (!rfn.name.eq("sym.main")) & (!rfn.name.eq("main")) {
            //        continue;
            //    }
            //    println!("  [*] Analyzing Value Sets");
            //    let fn_analyzer = FnAnalyzer::from((*rfn).clone());
            //    let a_store_fn = fn_analyzer.analyze_rfn();
            //    for (a_loc, strided_interval) in a_store_fn.store {
            //        if let A_Loc{addr: AbstractAddress::Node{..}, ..} = a_loc {
            //            continue;
            //        };
            //        println!("{}", a_loc);
            //        println!("Strided Interval: {}", strided_interval);
            //    };
            //}

            //{
                //// Expreimental reference marking pass
                //println!("  [*] Unstable> Marking References");
                //let mut rmark = mark_refs::ReferenceMarker { };
                //rmark.resolve_refs(&mut rfn.ssa);
            //}

            let mut fname = PathBuf::from(&dir);
            fname.push(rfn.name.as_ref());

            let fn_ir_str = {
                ///////////////////////////
                // Write out the IR file
                //////////////////////////
                println!("  [*] Writing out IR");
                let mut res = String::new();
                ir_writer::emit_il(&mut res, Some(rfn.name.to_string()), rfn.ssa()).unwrap();
                let mut ff = File::create(&fname).expect("Unable to create file");
                write!(ff, "{}", res).expect("Error writing to file");
                writeln!(ffm, "{}", res).expect("Error writing to file");
                // Set as a comment in radare2
                match rmod.source.as_mut().unwrap().send(format!("CC, {} @ {}", fname.to_str().unwrap(), addr)) {
                    Ok(_) => {},
                    Err(e) => println!("{:?}", e),
                };
                res
            };

            {
                //////////////////////////////
                // Try parsing the IR file
                /////////////////////////////
                println!("  [*] Testing IR parser");
                let parsed = parse_il(&fn_ir_str, regfile.clone());
                let mut res = String::new();
                ir_writer::emit_il(&mut res, Some((*rfn.name).to_owned()), &parsed).unwrap();
                for (orig, roundtrip) in fn_ir_str.lines().zip(res.lines()) {
                    if orig != roundtrip {
                        println!("  FAILED TO ROUND-TRIP: \"{}\" => \"{}\"", orig, roundtrip);
                    }
                }
            }

            {
                ////////////////////////
                // Generate DOT file
                ///////////////////////
                println!("  [*] Generating dot");
                fname.set_extension("dot");
                let mut df = File::create(&fname).expect("Unable to create .dot file");
                let dot = dot::emit_dot(rfn.ssa());
                writeln!(df, "{}", dot).expect("Error writing to file");
            }

            {
                ////////////////////////
                // Generate pseudo-C code
                ///////////////////////
                println!("  [*] Generating psuedo code");
                fname.set_extension("c");
                let mut df = File::create(&fname).expect("Unable to create .dot file");
                let ast = c_simple_ast_builder::CASTBuilder::recover_code(&rfn);
                let code = ast.to_c_ast().print();
                writeln!(df, "{}", code).expect("Error writing to file");
            }
        }

        match rmod.source.as_mut().unwrap().send("e scr.color=true".to_string()) {
            Ok(()) => {},
            Err(e) => println!("{:?}", e),
        }
    }
}

// Filters the functions that were in Radeco output AND requested by user
fn filter_with<'a>(all_funcs: &Vec<(u64, &'a str)>,
                   requested: &Vec<&'a str>)
                   -> Vec<(u64, &'a str)> {

    all_funcs.iter()
        .filter(|&&(_, name)| requested.iter().any(|user_req| &name == user_req))
        .map(|&(addr, name)| (addr, name))
        .collect()
}
<commit_msg>Flatten directory of output of minidec<commit_after>#[cfg(feature="trace_log")] extern crate env_logger;

extern crate radeco_lib;
extern crate r2pipe;
extern crate r2api;
extern crate petgraph;

mod cli;

use std::env;
use std::fs::{self, File};
use std::io::Write;
use std::path::PathBuf;
use std::process;

use radeco_lib::analysis::cse::cse::CSE;
use radeco_lib::analysis::sccp;
//use radeco_lib::analysis::valueset::analyzer_wysinwyx::FnAnalyzer;
//use radeco_lib::analysis::valueset::mem_structs::{A_Loc,AbstractAddress};
use radeco_lib::analysis::interproc::fixcall::CallFixer;
use radeco_lib::frontend::radeco_containers::ProjectLoader;
use radeco_lib::middle::{dce, dot};
use radeco_lib::middle::ir_writer;
use radeco_lib::middle::ir_reader::parse_il;
use radeco_lib::middle::ssa::verifier;
use radeco_lib::backend::lang_c::{c_simple_ast, c_simple_ast_builder};

//use radeco_lib::analysis::mark_refs;

const USAGE: &'static str = "
Usage: minidec [-f <names>...] <target>

Options:
    -f, --functions  Analayze only some functions
";

fn main() {
    #[cfg(feature="trace_log")] env_logger::init();

    let requested_functions = cli::init_for_args(USAGE);

    let proj_name = env::args().nth(env::args().len() - 1).unwrap();
    let mut rproj = {
        ProjectLoader::new().path(&proj_name).load()
    };
    let regfile = rproj.regfile().clone();
    for mut xy in rproj.iter_mut() {
        let rmod = &mut xy.module;
        let mut dir = PathBuf::from(".");
        dir.push(format!("{}_out", proj_name));
        fs::create_dir_all(&dir).expect("Failed to create directory");

        // Reduce the complexity of rmod.functions to just a vec of (u64,&String)
        // for easier extraction and matching

        // Analyze preserved for all functions.
        {
            println!("[*] Fixing Callee Information");
            let bp_name = regfile.get_name_by_alias(&"BP".to_string());
            let bp_name = bp_name.map(|s| s.to_owned());
            let sp_name = regfile.get_name_by_alias(&"SP".to_string());
            let sp_name = sp_name.map(|s| s.to_owned());
            let mut callfixer = CallFixer::new(rmod, bp_name, sp_name);
            callfixer.rounded_analysis();
        }

        // Fix call sites
        radeco_lib::analysis::functions::fix_ssa_opcalls::go(rmod);

        // Infer calling conventions
        radeco_lib::analysis::functions::infer_regusage::run(rmod, &*regfile);

        // Filter the data if the user provided some args to be matched upon
        let matched_func_addrs = if requested_functions.len() != 0 {

            //XXX Impl in more efficient way
            let mut matched_func_vec: Vec<(u64, &str)> =
                rmod.iter().map(|_f| {
                    let f = _f.function.1;
                    (f.offset.clone(), &*f.name)
                }).collect();

            let all_func_names: Vec<(&str)> =
                matched_func_vec.iter().map(|&(_, name)| name).collect();
            matched_func_vec = filter_with(&matched_func_vec,
                                           &requested_functions.iter().map(|s| &s[..]).collect::<Vec<_>>());
            cli::print_match_summary(&matched_func_vec,
                                     &requested_functions.iter().map(|s| &s[..]).collect::<Vec<_>>(),
                                     &all_func_names);
            matched_func_vec.into_iter().map(|(addr, _)| addr).collect::<Vec<_>>()
        } else {
            Vec::new()
        };

        // Main file to contain IRs of all rfns
        let mut ffm = {
            let mut fname = PathBuf::from(&dir);
            fname.push("main");
            File::create(&fname).expect("Unable to create file")
        };

        for addr in matched_func_addrs {

            let ref mut rfn = rmod.functions.get_mut(&addr).unwrap();

            println!("[+] Analyzing: {} @ {:#x}", rfn.name, addr);
            {
                println!("  [*] Eliminating Dead Code");
                dce::collect(rfn.ssa_mut());
            }
            let mut ssa = {
                // Constant Propagation (sccp)
                println!("  [*] Propagating Constants");
                let mut analyzer = sccp::Analyzer::new(rfn.ssa_mut());
                analyzer.analyze();
                analyzer.emit_ssa()
            };
            {
                println!("  [*] Eliminating More DeadCode");
                dce::collect(&mut ssa);
            }
            *rfn.ssa_mut() = ssa;
            {
                // Common SubExpression Elimination (cse)
                println!("  [*] Eliminating Common SubExpressions");
                let mut cse = CSE::new(rfn.ssa_mut());
                cse.run();
            }
            {
                // Verify SSA
                println!("  [*] Verifying SSA's Validity");
                match verifier::verify(rfn.ssa()) {
                    Err(e) => {
                        println!("  [*] Found Error: {}", e);
                        process::exit(255);
                    }
                    Ok(_) => {  }
                }
            }
            {
                // TODO
                // // Building memory SSA.
                // let _memory_ssa = {
                //     // Generate MemorySSA
                //     println!("  [*] Generating Memory SSA");
                //     let mut mssa = MemorySSA::new(rfn.ssa());
                //     mssa.gather_variables(rfn.datarefs(), &rfn.locals(),
                //                           &rfn.call_refs(&rmod.callgraph));
                //     mssa.run();
                //     mssa
                // };
            }
            //if false {
            //    if (!rfn.name.eq("sym.main")) & (!rfn.name.eq("main")) {
            //        continue;
            //    }
            //    println!("  [*] Analyzing Value Sets");
            //    let fn_analyzer = FnAnalyzer::from((*rfn).clone());
            //    let a_store_fn = fn_analyzer.analyze_rfn();
            //    for (a_loc, strided_interval) in a_store_fn.store {
            //        if let A_Loc{addr: AbstractAddress::Node{..}, ..} = a_loc {
            //            continue;
            //        };
            //        println!("{}", a_loc);
            //        println!("Strided Interval: {}", strided_interval);
            //    };
            //}

            //{
                //// Expreimental reference marking pass
                //println!("  [*] Unstable> Marking References");
                //let mut rmark = mark_refs::ReferenceMarker { };
                //rmark.resolve_refs(&mut rfn.ssa);
            //}

            let mut fname = PathBuf::from(&dir);
            fname.push(rfn.name.as_ref());

            let fn_ir_str = {
                ///////////////////////////
                // Write out the IR file
                //////////////////////////
                println!("  [*] Writing out IR");
                let mut res = String::new();
                ir_writer::emit_il(&mut res, Some(rfn.name.to_string()), rfn.ssa()).unwrap();
                let mut ff = File::create(&fname).expect("Unable to create file");
                write!(ff, "{}", res).expect("Error writing to file");
                writeln!(ffm, "{}", res).expect("Error writing to file");
                // Set as a comment in radare2
                match rmod.source.as_mut().unwrap().send(format!("CC, {} @ {}", fname.to_str().unwrap(), addr)) {
                    Ok(_) => {},
                    Err(e) => println!("{:?}", e),
                };
                res
            };

            {
                //////////////////////////////
                // Try parsing the IR file
                /////////////////////////////
                println!("  [*] Testing IR parser");
                let parsed = parse_il(&fn_ir_str, regfile.clone());
                let mut res = String::new();
                ir_writer::emit_il(&mut res, Some((*rfn.name).to_owned()), &parsed).unwrap();
                for (orig, roundtrip) in fn_ir_str.lines().zip(res.lines()) {
                    if orig != roundtrip {
                        println!("  FAILED TO ROUND-TRIP: \"{}\" => \"{}\"", orig, roundtrip);
                    }
                }
            }

            {
                ////////////////////////
                // Generate DOT file
                ///////////////////////
                println!("  [*] Generating dot");
                fname.set_extension("dot");
                let mut df = File::create(&fname).expect("Unable to create .dot file");
                let dot = dot::emit_dot(rfn.ssa());
                writeln!(df, "{}", dot).expect("Error writing to file");
            }

            {
                ////////////////////////
                // Generate pseudo-C code
                ///////////////////////
                println!("  [*] Generating psuedo code");
                fname.set_extension("c");
                let mut df = File::create(&fname).expect("Unable to create .dot file");
                let ast = c_simple_ast_builder::CASTBuilder::recover_code(&rfn);
                let code = ast.to_c_ast().print();
                writeln!(df, "{}", code).expect("Error writing to file");
            }
        }

        match rmod.source.as_mut().unwrap().send("e scr.color=true".to_string()) {
            Ok(()) => {},
            Err(e) => println!("{:?}", e),
        }
    }
}

// Filters the functions that were in Radeco output AND requested by user
fn filter_with<'a>(all_funcs: &Vec<(u64, &'a str)>,
                   requested: &Vec<&'a str>)
                   -> Vec<(u64, &'a str)> {

    all_funcs.iter()
        .filter(|&&(_, name)| requested.iter().any(|user_req| &name == user_req))
        .map(|&(addr, name)| (addr, name))
        .collect()
}
<|endoftext|>


<commit_before>extern crate piston;
extern crate dyon;
extern crate current;
extern crate graphics;

use std::any::Any;
use std::sync::Arc;
use self::dyon::*;
use self::current::Current;
use self::piston::input::*;
use self::piston::window::*;
use self::graphics::{Context, Graphics};

pub const NO_EVENT: &'static str = "No event";

pub fn add_functions<W: Any + AdvancedWindow>(module: &mut Module) {
    module.add(Arc::new("render".into()), render, PreludeFunction {
        lts: vec![],
        tys: vec![],
        ret: Type::Bool
    });
    module.add(Arc::new("update".into()), update, PreludeFunction {
        lts: vec![],
        tys: vec![],
        ret: Type::Bool
    });
    module.add(Arc::new("press".into()), press, PreludeFunction {
        lts: vec![],
        tys: vec![],
        ret: Type::Bool
    });
    module.add(Arc::new("release".into()), release, PreludeFunction {
        lts: vec![],
        tys: vec![],
        ret: Type::Bool
    });
    module.add(Arc::new("focus".into()), focus, PreludeFunction {
        lts: vec![],
        tys: vec![],
        ret: Type::Bool,
    });
    module.add(Arc::new("focus_arg".into()), focus_arg, PreludeFunction {
        lts: vec![],
        tys: vec![],
        ret: Type::Option(Box::new(Type::Bool)),
    });
    module.add(Arc::new("set_title".into()),
        set_title::<W>, PreludeFunction {
            lts: vec![Lt::Default],
            tys: vec![Type::Text],
            ret: Type::Void
        });
    module.add(Arc::new("update_dt".into()),
        update_dt, PreludeFunction {
            lts: vec![],
            tys: vec![],
            ret: Type::Option(Box::new(Type::F64))
        });
    module.add(Arc::new("press_keyboard_key".into()),
        press_keyboard_key, PreludeFunction {
            lts: vec![],
            tys: vec![],
            ret: Type::Option(Box::new(Type::F64))
        });
    module.add(Arc::new("release_keyboard_key".into()),
        release_keyboard_key, PreludeFunction {
            lts: vec![],
            tys: vec![],
            ret: Type::Option(Box::new(Type::F64))
        });
}

pub fn render(rt: &mut Runtime) -> Result<(), String> {
    rt.push(unsafe { Current::<Option<Event>>::new()
        .as_ref().expect(NO_EVENT).render_args().is_some() });
    Ok(())
}

pub fn update(rt: &mut Runtime) -> Result<(), String> {
    rt.push(unsafe { Current::<Option<Event>>::new()
        .as_ref().expect(NO_EVENT).update_args().is_some() });
    Ok(())
}

pub fn press(rt: &mut Runtime) -> Result<(), String> {
    rt.push(unsafe { Current::<Option<Event>>::new()
        .as_ref().expect(NO_EVENT).press_args().is_some() });
    Ok(())
}

pub fn release(rt: &mut Runtime) -> Result<(), String> {
    rt.push(unsafe { Current::<Option<Event>>::new()
        .as_ref().expect(NO_EVENT).release_args().is_some() });
    Ok(())
}

pub fn focus(rt: &mut Runtime) -> Result<(), String> {
    rt.push(unsafe { Current::<Option<Event>>::new()
        .as_ref().expect(NO_EVENT).focus_args().is_some() });
    Ok(())
}

pub fn focus_arg(rt: &mut Runtime) -> Result<(), String> {
    rt.push(unsafe { Current::<Option<Event>>::new()
        .as_ref().expect(NO_EVENT).focus_args() });
    Ok(())
}

pub fn update_dt(rt: &mut Runtime) -> Result<(), String> {
    rt.push(unsafe { Current::<Option<Event>>::new()
        .as_ref().expect(NO_EVENT).update_args().map(|args| args.dt) });
    Ok(())
}

pub fn press_keyboard_key(rt: &mut Runtime) -> Result<(), String> {
    let e = unsafe { &*Current::<Option<Event>>::new() };
    if let &Some(ref e) = e {
        if let Some(Button::Keyboard(key)) = e.press_args() {
            rt.push(Some(key as u64 as f64));
        } else {
            rt.push::<Option<f64>>(None);
        }
        Ok(())
    } else {
        Err(NO_EVENT.into())
    }
}

pub fn release_keyboard_key(rt: &mut Runtime) -> Result<(), String> {
    let e = unsafe { &*Current::<Option<Event>>::new() };
    if let &Some(ref e) = e {
        if let Some(Button::Keyboard(key)) = e.release_args() {
            rt.push(Some(key as u64 as f64));
        } else {
            rt.push::<Option<f64>>(None);
        }
        Ok(())
    } else {
        Err(NO_EVENT.into())
    }
}

pub fn set_title<W: Any + AdvancedWindow>(rt: &mut Runtime) -> Result<(), String> {
    use std::sync::Arc;

    let window = unsafe { &mut *Current::<W>::new() };
    let title: Arc<String> = try!(rt.pop());
    window.set_title((*title).clone());
    Ok(())
}

pub fn draw_2d<G: Graphics>(rt: &mut Runtime, c: Context, g: &mut G) -> Result<(), String> {
    use self::graphics::*;

    let draw_list = rt.stack.pop().expect("There is no value on the stack");
    let arr = rt.resolve(&draw_list);
    if let &Variable::Array(ref arr) = arr {
        for it in &**arr {
            let it = rt.resolve(it);
            if let &Variable::Array(ref it) = it {
                let ty: Arc<String> = try!(rt.var(&it[0]));
                match &**ty {
                    "clear" => {
                        let color: [f32; 4] = try!(rt.var_vec4(&it[1]));
                        clear(color, g);
                    }
                    "line_color_radius_from_to" => {
                        let color: [f32; 4] = try!(rt.var_vec4(&it[1]));
                        let radius: f64 = try!(rt.var(&it[2]));
                        let from: [f64; 2] = try!(rt.var_vec4(&it[3]));
                        let to: [f64; 2] = try!(rt.var_vec4(&it[4]));
                        line(color, radius, [from[0], from[1], to[0], to[1]], c.transform, g);
                    }
                    "rectangle_color_corner_size" => {
                        let color: [f32; 4] = try!(rt.var_vec4(&it[1]));
                        let corner: [f64; 2] = try!(rt.var_vec4(&it[2]));
                        let size: [f64; 2] = try!(rt.var_vec4(&it[3]));
                        rectangle(color, [corner[0], corner[1], size[0], size[1]], c.transform, g);
                    }
                    "ellipse_color_corner_size_resolution" => {
                        let color: [f32; 4] = try!(rt.var_vec4(&it[1]));
                        let corner: [f64; 2] = try!(rt.var_vec4(&it[2]));
                        let size: [f64; 2] = try!(rt.var_vec4(&it[3]));
                        let resolution: u32 = try!(rt.var(&it[4]));
                        Ellipse::new(color)
                        .resolution(resolution as u32)
                        .draw([corner[0], corner[1], size[0], size[1]], &c.draw_state, c.transform, g);
                    }
                    _ => {}
                }
            }
        }
    }
    return Ok(())
}
<commit_msg>Add "transfrom_rx_ry"<commit_after>extern crate piston;
extern crate dyon;
extern crate current;
extern crate graphics;

use std::any::Any;
use std::sync::Arc;
use self::dyon::*;
use self::current::Current;
use self::piston::input::*;
use self::piston::window::*;
use self::graphics::{Context, Graphics};

pub const NO_EVENT: &'static str = "No event";

pub fn add_functions<W: Any + AdvancedWindow>(module: &mut Module) {
    module.add(Arc::new("render".into()), render, PreludeFunction {
        lts: vec![],
        tys: vec![],
        ret: Type::Bool
    });
    module.add(Arc::new("update".into()), update, PreludeFunction {
        lts: vec![],
        tys: vec![],
        ret: Type::Bool
    });
    module.add(Arc::new("press".into()), press, PreludeFunction {
        lts: vec![],
        tys: vec![],
        ret: Type::Bool
    });
    module.add(Arc::new("release".into()), release, PreludeFunction {
        lts: vec![],
        tys: vec![],
        ret: Type::Bool
    });
    module.add(Arc::new("focus".into()), focus, PreludeFunction {
        lts: vec![],
        tys: vec![],
        ret: Type::Bool,
    });
    module.add(Arc::new("focus_arg".into()), focus_arg, PreludeFunction {
        lts: vec![],
        tys: vec![],
        ret: Type::Option(Box::new(Type::Bool)),
    });
    module.add(Arc::new("set_title".into()),
        set_title::<W>, PreludeFunction {
            lts: vec![Lt::Default],
            tys: vec![Type::Text],
            ret: Type::Void
        });
    module.add(Arc::new("update_dt".into()),
        update_dt, PreludeFunction {
            lts: vec![],
            tys: vec![],
            ret: Type::Option(Box::new(Type::F64))
        });
    module.add(Arc::new("press_keyboard_key".into()),
        press_keyboard_key, PreludeFunction {
            lts: vec![],
            tys: vec![],
            ret: Type::Option(Box::new(Type::F64))
        });
    module.add(Arc::new("release_keyboard_key".into()),
        release_keyboard_key, PreludeFunction {
            lts: vec![],
            tys: vec![],
            ret: Type::Option(Box::new(Type::F64))
        });
}

pub fn render(rt: &mut Runtime) -> Result<(), String> {
    rt.push(unsafe { Current::<Option<Event>>::new()
        .as_ref().expect(NO_EVENT).render_args().is_some() });
    Ok(())
}

pub fn update(rt: &mut Runtime) -> Result<(), String> {
    rt.push(unsafe { Current::<Option<Event>>::new()
        .as_ref().expect(NO_EVENT).update_args().is_some() });
    Ok(())
}

pub fn press(rt: &mut Runtime) -> Result<(), String> {
    rt.push(unsafe { Current::<Option<Event>>::new()
        .as_ref().expect(NO_EVENT).press_args().is_some() });
    Ok(())
}

pub fn release(rt: &mut Runtime) -> Result<(), String> {
    rt.push(unsafe { Current::<Option<Event>>::new()
        .as_ref().expect(NO_EVENT).release_args().is_some() });
    Ok(())
}

pub fn focus(rt: &mut Runtime) -> Result<(), String> {
    rt.push(unsafe { Current::<Option<Event>>::new()
        .as_ref().expect(NO_EVENT).focus_args().is_some() });
    Ok(())
}

pub fn focus_arg(rt: &mut Runtime) -> Result<(), String> {
    rt.push(unsafe { Current::<Option<Event>>::new()
        .as_ref().expect(NO_EVENT).focus_args() });
    Ok(())
}

pub fn update_dt(rt: &mut Runtime) -> Result<(), String> {
    rt.push(unsafe { Current::<Option<Event>>::new()
        .as_ref().expect(NO_EVENT).update_args().map(|args| args.dt) });
    Ok(())
}

pub fn press_keyboard_key(rt: &mut Runtime) -> Result<(), String> {
    let e = unsafe { &*Current::<Option<Event>>::new() };
    if let &Some(ref e) = e {
        if let Some(Button::Keyboard(key)) = e.press_args() {
            rt.push(Some(key as u64 as f64));
        } else {
            rt.push::<Option<f64>>(None);
        }
        Ok(())
    } else {
        Err(NO_EVENT.into())
    }
}

pub fn release_keyboard_key(rt: &mut Runtime) -> Result<(), String> {
    let e = unsafe { &*Current::<Option<Event>>::new() };
    if let &Some(ref e) = e {
        if let Some(Button::Keyboard(key)) = e.release_args() {
            rt.push(Some(key as u64 as f64));
        } else {
            rt.push::<Option<f64>>(None);
        }
        Ok(())
    } else {
        Err(NO_EVENT.into())
    }
}

pub fn set_title<W: Any + AdvancedWindow>(rt: &mut Runtime) -> Result<(), String> {
    use std::sync::Arc;

    let window = unsafe { &mut *Current::<W>::new() };
    let title: Arc<String> = try!(rt.pop());
    window.set_title((*title).clone());
    Ok(())
}

/// Helper method for drawing 2D in Dyon environment.
pub fn draw_2d<G: Graphics>(rt: &mut Runtime, c: Context, g: &mut G) -> Result<(), String> {
    use self::graphics::*;
    use self::graphics::types::Matrix2d;

    let draw_list = rt.stack.pop().expect("There is no value on the stack");
    let arr = rt.resolve(&draw_list);
    let mut transform = c.transform;
    if let &Variable::Array(ref arr) = arr {
        for it in &**arr {
            let it = rt.resolve(it);
            if let &Variable::Array(ref it) = it {
                let ty: Arc<String> = try!(rt.var(&it[0]));
                match &**ty {
                    "clear" => {
                        let color: [f32; 4] = try!(rt.var_vec4(&it[1]));
                        clear(color, g);
                    }
                    "transform_rx_ry" => {
                        // Changes transform matrix.
                        let rx: [f32; 4] = try!(rt.var_vec4(&it[1]));
                        let ry: [f32; 4] = try!(rt.var_vec4(&it[2]));
                        let t: Matrix2d = [
                            [rx[0] as f64, rx[1] as f64, rx[2] as f64],
                            [ry[0] as f64, ry[1] as f64, ry[2] as f64]
                        ];
                        transform = math::multiply(c.transform, t);
                    }
                    "line_color_radius_from_to" => {
                        let color: [f32; 4] = try!(rt.var_vec4(&it[1]));
                        let radius: f64 = try!(rt.var(&it[2]));
                        let from: [f64; 2] = try!(rt.var_vec4(&it[3]));
                        let to: [f64; 2] = try!(rt.var_vec4(&it[4]));
                        line(color, radius, [from[0], from[1], to[0], to[1]], transform, g);
                    }
                    "rectangle_color_corner_size" => {
                        let color: [f32; 4] = try!(rt.var_vec4(&it[1]));
                        let corner: [f64; 2] = try!(rt.var_vec4(&it[2]));
                        let size: [f64; 2] = try!(rt.var_vec4(&it[3]));
                        rectangle(color, [corner[0], corner[1], size[0], size[1]], transform, g);
                    }
                    "ellipse_color_corner_size_resolution" => {
                        let color: [f32; 4] = try!(rt.var_vec4(&it[1]));
                        let corner: [f64; 2] = try!(rt.var_vec4(&it[2]));
                        let size: [f64; 2] = try!(rt.var_vec4(&it[3]));
                        let resolution: u32 = try!(rt.var(&it[4]));
                        Ellipse::new(color)
                        .resolution(resolution as u32)
                        .draw([corner[0], corner[1], size[0], size[1]], &c.draw_state, transform, g);
                    }
                    _ => {}
                }
            }
        }
    }
    return Ok(())
}
<|endoftext|>