<commit_before>use std::path::{Path, PathBuf};

use config::Config;
use errors::Result;

/// Takes a full path to a file and returns only the components after the first `content` directory
/// Will not return the filename as last component
pub fn find_content_components<P: AsRef<Path>>(path: P) -> Vec<String> {
    let path = path.as_ref();
    let mut is_in_content = false;
    let mut components = vec![];

    for section in path.parent().unwrap().components() {
        let component = section.as_os_str().to_string_lossy();

        if is_in_content {
            components.push(component.to_string());
            continue;
        }

        if component == "content" {
            is_in_content = true;
        }
    }

    components
}

/// Struct that contains all the information about the actual file
#[derive(Debug, Clone, PartialEq)]
pub struct FileInfo {
    /// The full path to the .md file
    pub path: PathBuf,
    /// The on-disk filename, will differ from the `name` when there is a language code in it
    pub filename: String,
    /// The name of the .md file without the extension, always `_index` for sections
    /// Doesn't contain the language if there was one in the filename
    pub name: String,
    /// The .md path, starting from the content directory, with `/` slashes
    pub relative: String,
    /// Path of the directory containing the .md file
    pub parent: PathBuf,
    /// Path of the grand parent directory for that file. Only used in sections to find subsections.
    pub grand_parent: Option<PathBuf>,
    /// The folder names to this section file, starting from the `content` directory
    /// For example a file at content/kb/solutions/blabla.md will have 2 components:
    /// `kb` and `solutions`
    pub components: Vec<String>,
    /// This is `parent` + `name`, used to find content referring to the same content but in
    /// various languages.
    pub canonical: PathBuf,
}

impl FileInfo {
    pub fn new_page(path: &Path, base_path: &PathBuf) -> FileInfo {
        let file_path = path.to_path_buf();
        let mut parent = file_path.parent().expect("Get parent of page").to_path_buf();
        let name = path.file_stem().unwrap().to_string_lossy().to_string();
        let mut components =
            find_content_components(&file_path.strip_prefix(base_path).unwrap_or(&file_path));
        let relative = if !components.is_empty() {
            format!("{}/{}.md", components.join("/"), name)
        } else {
            format!("{}.md", name)
        };

        // If we have a folder with an asset, don't consider it as a component
        // Splitting on `.` as we might have a language so it isn't *only* index but also index.fr
        // etc
        if !components.is_empty() && name.split('.').collect::<Vec<_>>()[0] == "index" {
            components.pop();
            // also set parent_path to grandparent instead
            parent = parent.parent().unwrap().to_path_buf();
        }

        FileInfo {
            filename: file_path.file_name().unwrap().to_string_lossy().to_string(),
            path: file_path,
            // We don't care about grand parent for pages
            grand_parent: None,
            canonical: parent.join(&name),
            parent,
            name,
            components,
            relative,
        }
    }

    pub fn new_section(path: &Path, base_path: &PathBuf) -> FileInfo {
        let file_path = path.to_path_buf();
        let parent = path.parent().expect("Get parent of section").to_path_buf();
        let name = path.file_stem().unwrap().to_string_lossy().to_string();
        let components =
            find_content_components(&file_path.strip_prefix(base_path).unwrap_or(&file_path));
        let relative = if !components.is_empty() {
            format!("{}/{}.md", components.join("/"), name)
        } else {
            format!("{}.md", name)
        };
        let grand_parent = parent.parent().map(|p| p.to_path_buf());

        FileInfo {
            filename: file_path.file_name().unwrap().to_string_lossy().to_string(),
            path: file_path,
            canonical: parent.join(&name),
            parent,
            grand_parent,
            name,
            components,
            relative,
        }
    }

    /// Look for a language in the filename.
    /// If a language has been found, update the name of the file in this struct to
    /// remove it and return the language code
    pub fn find_language(&mut self, config: &Config) -> Result<String> {
        // No languages? Nothing to do
        if !config.is_multilingual() {
            return Ok(config.default_language.clone());
        }

        if !self.name.contains('.') {
            return Ok(config.default_language.clone());
        }

        // Go with the assumption that no one is using `.` in filenames when using i18n
        // We can document that
        let mut parts: Vec<String> = self.name.splitn(2, '.').map(|s| s.to_string()).collect();

        // The language code is not present in the config: typo or the user forgot to add it to the
        // config
        if !config.languages_codes().contains(&parts[1].as_ref()) {
            bail!("File {:?} has a language code of {} which isn't present in the config.toml `languages`", self.path, parts[1]);
        }

        self.name = parts.swap_remove(0);
        self.canonical = self.parent.join(&self.name);
        let lang = parts.swap_remove(0);

        Ok(lang)
    }
}

#[doc(hidden)]
impl Default for FileInfo {
    fn default() -> FileInfo {
        FileInfo {
            path: PathBuf::new(),
            parent: PathBuf::new(),
            grand_parent: None,
            filename: String::new(),
            name: String::new(),
            components: vec![],
            relative: String::new(),
            canonical: PathBuf::new(),
        }
    }
}

#[cfg(test)]
mod tests {
    use std::path::{Path, PathBuf};

    use config::{Config, Language};

    use super::{find_content_components, FileInfo};

    #[test]
    fn can_find_content_components() {
        let res =
            find_content_components("/home/vincent/code/site/content/posts/tutorials/python.md");
        assert_eq!(res, ["posts".to_string(), "tutorials".to_string()]);
    }

    #[test]
    fn can_find_components_in_page_with_assets() {
        let file = FileInfo::new_page(
            &Path::new("/home/vincent/code/site/content/posts/tutorials/python/index.md"),
            &PathBuf::new(),
        );
        assert_eq!(file.components, ["posts".to_string(), "tutorials".to_string()]);
    }

    #[test]
    fn doesnt_fail_with_multiple_content_directories() {
        let file = FileInfo::new_page(
            &Path::new("/home/vincent/code/content/site/content/posts/tutorials/python/index.md"),
            &PathBuf::from("/home/vincent/code/content/site"),
        );
        assert_eq!(file.components, ["posts".to_string(), "tutorials".to_string()]);
    }

    #[test]
    fn can_find_valid_language_in_page() {
        let mut config = Config::default();
        config.languages.push(Language { code: String::from("fr"), rss: false, search: false });
        let mut file = FileInfo::new_page(
            &Path::new("/home/vincent/code/site/content/posts/tutorials/python.fr.md"),
            &PathBuf::new(),
        );
        let res = file.find_language(&config);
        assert!(res.is_ok());
        assert_eq!(res.unwrap(), "fr");
    }

    #[test]
    fn can_find_valid_language_in_page_with_assets() {
        let mut config = Config::default();
        config.languages.push(Language { code: String::from("fr"), rss: false, search: false });
        let mut file = FileInfo::new_page(
            &Path::new("/home/vincent/code/site/content/posts/tutorials/python/index.fr.md"),
            &PathBuf::new(),
        );
        assert_eq!(file.components, ["posts".to_string(), "tutorials".to_string()]);
        let res = file.find_language(&config);
        assert!(res.is_ok());
        assert_eq!(res.unwrap(), "fr");
    }

    #[test]
    fn do_nothing_on_unknown_language_in_page_with_i18n_off() {
        let config = Config::default();
        let mut file = FileInfo::new_page(
            &Path::new("/home/vincent/code/site/content/posts/tutorials/python.fr.md"),
            &PathBuf::new(),
        );
        let res = file.find_language(&config);
        assert!(res.is_ok());
        assert_eq!(res.unwrap(), config.default_language);
    }

    #[test]
    fn errors_on_unknown_language_in_page_with_i18n_on() {
        let mut config = Config::default();
        config.languages.push(Language { code: String::from("it"), rss: false, search: false });
        let mut file = FileInfo::new_page(
            &Path::new("/home/vincent/code/site/content/posts/tutorials/python.fr.md"),
            &PathBuf::new(),
        );
        let res = file.find_language(&config);
        assert!(res.is_err());
    }

    #[test]
    fn can_find_valid_language_in_section() {
        let mut config = Config::default();
        config.languages.push(Language { code: String::from("fr"), rss: false, search: false });
        let mut file = FileInfo::new_section(
            &Path::new("/home/vincent/code/site/content/posts/tutorials/_index.fr.md"),
            &PathBuf::new(),
        );
        let res = file.find_language(&config);
        assert!(res.is_ok());
        assert_eq!(res.unwrap(), "fr");
    }
}
<commit_msg>Compute canonical path before adjusting parent path (#856)<commit_after>use std::path::{Path, PathBuf};

use config::Config;
use errors::Result;

/// Takes a full path to a file and returns only the components after the first `content` directory
/// Will not return the filename as last component
pub fn find_content_components<P: AsRef<Path>>(path: P) -> Vec<String> {
    let path = path.as_ref();
    let mut is_in_content = false;
    let mut components = vec![];

    for section in path.parent().unwrap().components() {
        let component = section.as_os_str().to_string_lossy();

        if is_in_content {
            components.push(component.to_string());
            continue;
        }

        if component == "content" {
            is_in_content = true;
        }
    }

    components
}

/// Struct that contains all the information about the actual file
#[derive(Debug, Clone, PartialEq)]
pub struct FileInfo {
    /// The full path to the .md file
    pub path: PathBuf,
    /// The on-disk filename, will differ from the `name` when there is a language code in it
    pub filename: String,
    /// The name of the .md file without the extension, always `_index` for sections
    /// Doesn't contain the language if there was one in the filename
    pub name: String,
    /// The .md path, starting from the content directory, with `/` slashes
    pub relative: String,
    /// Path of the directory containing the .md file
    pub parent: PathBuf,
    /// Path of the grand parent directory for that file. Only used in sections to find subsections.
    pub grand_parent: Option<PathBuf>,
    /// The folder names to this section file, starting from the `content` directory
    /// For example a file at content/kb/solutions/blabla.md will have 2 components:
    /// `kb` and `solutions`
    pub components: Vec<String>,
    /// This is `parent` + `name`, used to find content referring to the same content but in
    /// various languages.
    pub canonical: PathBuf,
}

impl FileInfo {
    pub fn new_page(path: &Path, base_path: &PathBuf) -> FileInfo {
        let file_path = path.to_path_buf();
        let mut parent = file_path.parent().expect("Get parent of page").to_path_buf();
        let name = path.file_stem().unwrap().to_string_lossy().to_string();
        let canonical = parent.join(&name);
        let mut components =
            find_content_components(&file_path.strip_prefix(base_path).unwrap_or(&file_path));
        let relative = if !components.is_empty() {
            format!("{}/{}.md", components.join("/"), name)
        } else {
            format!("{}.md", name)
        };

        // If we have a folder with an asset, don't consider it as a component
        // Splitting on `.` as we might have a language so it isn't *only* index but also index.fr
        // etc
        if !components.is_empty() && name.split('.').collect::<Vec<_>>()[0] == "index" {
            components.pop();
            // also set parent_path to grandparent instead
            parent = parent.parent().unwrap().to_path_buf();
        }

        FileInfo {
            filename: file_path.file_name().unwrap().to_string_lossy().to_string(),
            path: file_path,
            // We don't care about grand parent for pages
            grand_parent: None,
            canonical,
            parent,
            name,
            components,
            relative,
        }
    }

    pub fn new_section(path: &Path, base_path: &PathBuf) -> FileInfo {
        let file_path = path.to_path_buf();
        let parent = path.parent().expect("Get parent of section").to_path_buf();
        let name = path.file_stem().unwrap().to_string_lossy().to_string();
        let components =
            find_content_components(&file_path.strip_prefix(base_path).unwrap_or(&file_path));
        let relative = if !components.is_empty() {
            format!("{}/{}.md", components.join("/"), name)
        } else {
            format!("{}.md", name)
        };
        let grand_parent = parent.parent().map(|p| p.to_path_buf());

        FileInfo {
            filename: file_path.file_name().unwrap().to_string_lossy().to_string(),
            path: file_path,
            canonical: parent.join(&name),
            parent,
            grand_parent,
            name,
            components,
            relative,
        }
    }

    /// Look for a language in the filename.
    /// If a language has been found, update the name of the file in this struct to
    /// remove it and return the language code
    pub fn find_language(&mut self, config: &Config) -> Result<String> {
        // No languages? Nothing to do
        if !config.is_multilingual() {
            return Ok(config.default_language.clone());
        }

        if !self.name.contains('.') {
            return Ok(config.default_language.clone());
        }

        // Go with the assumption that no one is using `.` in filenames when using i18n
        // We can document that
        let mut parts: Vec<String> = self.name.splitn(2, '.').map(|s| s.to_string()).collect();

        // The language code is not present in the config: typo or the user forgot to add it to the
        // config
        if !config.languages_codes().contains(&parts[1].as_ref()) {
            bail!("File {:?} has a language code of {} which isn't present in the config.toml `languages`", self.path, parts[1]);
        }

        self.name = parts.swap_remove(0);
        self.canonical = self.path.parent().expect("Get parent of page path").join(&self.name);
        let lang = parts.swap_remove(0);

        Ok(lang)
    }
}

#[doc(hidden)]
impl Default for FileInfo {
    fn default() -> FileInfo {
        FileInfo {
            path: PathBuf::new(),
            parent: PathBuf::new(),
            grand_parent: None,
            filename: String::new(),
            name: String::new(),
            components: vec![],
            relative: String::new(),
            canonical: PathBuf::new(),
        }
    }
}

#[cfg(test)]
mod tests {
    use std::path::{Path, PathBuf};

    use config::{Config, Language};

    use super::{find_content_components, FileInfo};

    #[test]
    fn can_find_content_components() {
        let res =
            find_content_components("/home/vincent/code/site/content/posts/tutorials/python.md");
        assert_eq!(res, ["posts".to_string(), "tutorials".to_string()]);
    }

    #[test]
    fn can_find_components_in_page_with_assets() {
        let file = FileInfo::new_page(
            &Path::new("/home/vincent/code/site/content/posts/tutorials/python/index.md"),
            &PathBuf::new(),
        );
        assert_eq!(file.components, ["posts".to_string(), "tutorials".to_string()]);
    }

    #[test]
    fn doesnt_fail_with_multiple_content_directories() {
        let file = FileInfo::new_page(
            &Path::new("/home/vincent/code/content/site/content/posts/tutorials/python/index.md"),
            &PathBuf::from("/home/vincent/code/content/site"),
        );
        assert_eq!(file.components, ["posts".to_string(), "tutorials".to_string()]);
    }

    #[test]
    fn can_find_valid_language_in_page() {
        let mut config = Config::default();
        config.languages.push(Language { code: String::from("fr"), rss: false, search: false });
        let mut file = FileInfo::new_page(
            &Path::new("/home/vincent/code/site/content/posts/tutorials/python.fr.md"),
            &PathBuf::new(),
        );
        let res = file.find_language(&config);
        assert!(res.is_ok());
        assert_eq!(res.unwrap(), "fr");
    }

    #[test]
    fn can_find_valid_language_in_page_with_assets() {
        let mut config = Config::default();
        config.languages.push(Language { code: String::from("fr"), rss: false, search: false });
        let mut file = FileInfo::new_page(
            &Path::new("/home/vincent/code/site/content/posts/tutorials/python/index.fr.md"),
            &PathBuf::new(),
        );
        assert_eq!(file.components, ["posts".to_string(), "tutorials".to_string()]);
        let res = file.find_language(&config);
        assert!(res.is_ok());
        assert_eq!(res.unwrap(), "fr");
    }

    #[test]
    fn do_nothing_on_unknown_language_in_page_with_i18n_off() {
        let config = Config::default();
        let mut file = FileInfo::new_page(
            &Path::new("/home/vincent/code/site/content/posts/tutorials/python.fr.md"),
            &PathBuf::new(),
        );
        let res = file.find_language(&config);
        assert!(res.is_ok());
        assert_eq!(res.unwrap(), config.default_language);
    }

    #[test]
    fn errors_on_unknown_language_in_page_with_i18n_on() {
        let mut config = Config::default();
        config.languages.push(Language { code: String::from("it"), rss: false, search: false });
        let mut file = FileInfo::new_page(
            &Path::new("/home/vincent/code/site/content/posts/tutorials/python.fr.md"),
            &PathBuf::new(),
        );
        let res = file.find_language(&config);
        assert!(res.is_err());
    }

    #[test]
    fn can_find_valid_language_in_section() {
        let mut config = Config::default();
        config.languages.push(Language { code: String::from("fr"), rss: false, search: false });
        let mut file = FileInfo::new_section(
            &Path::new("/home/vincent/code/site/content/posts/tutorials/_index.fr.md"),
            &PathBuf::new(),
        );
        let res = file.find_language(&config);
        assert!(res.is_ok());
        assert_eq!(res.unwrap(), "fr");
    }

    /// Regression test for https://github.com/getzola/zola/pull/856.
    #[test]
    fn correct_canonical_for_index() {
        let file = FileInfo::new_page(
            &Path::new("/home/vincent/code/site/content/posts/tutorials/python/index.md"),
            &PathBuf::new(),
        );
        assert_eq!(file.canonical, Path::new("/home/vincent/code/site/content/posts/tutorials/python/index"));
    }

    /// Regression test for https://github.com/getzola/zola/pull/856.
    #[test]
    fn correct_canonical_after_find_language() {
        let mut config = Config::default();
        config.languages.push(Language { code: String::from("fr"), rss: false, search: false });
        let mut file = FileInfo::new_page(
            &Path::new("/home/vincent/code/site/content/posts/tutorials/python/index.fr.md"),
            &PathBuf::new(),
        );
        let res = file.find_language(&config);
        assert!(res.is_ok());
        assert_eq!(file.canonical, Path::new("/home/vincent/code/site/content/posts/tutorials/python/index"));
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

<%! from data import Keyword, to_rust_ident %>

<%def name="longhand(name, **kwargs)">
    <%call expr="raw_longhand(name, **kwargs)">
        ${caller.body()}
        % if not data.longhands_by_name[name].derived_from:
            pub fn parse_specified(context: &ParserContext, input: &mut Parser)
                               -> Result<DeclaredValue<SpecifiedValue>, ()> {
                parse(context, input).map(DeclaredValue::Value)
            }
        % endif
    </%call>
</%def>

<%def name="predefined_type(name, type, initial_value, parse_method='parse', products='gecko servo')">
    <%self:longhand name="${name}" products="${products}">
        #[allow(unused_imports)]
        use app_units::Au;
        pub type SpecifiedValue = specified::${type};
        pub mod computed_value {
            pub use values::computed::${type} as T;
        }
        #[inline] pub fn get_initial_value() -> computed_value::T { ${initial_value} }
        #[inline] pub fn parse(_context: &ParserContext, input: &mut Parser)
                               -> Result<SpecifiedValue, ()> {
            specified::${type}::${parse_method}(input)
        }
    </%self:longhand>
</%def>

<%def name="raw_longhand(*args, **kwargs)">
    <%
        property = data.declare_longhand(*args, **kwargs)
        if property is None:
            return ""
    %>
    pub mod ${property.ident} {
        #![allow(unused_imports)]
        % if not property.derived_from:
            use cssparser::Parser;
            use parser::ParserContext;
            use properties::{CSSWideKeyword, DeclaredValue, Shorthand};
        % endif
        use error_reporting::ParseErrorReporter;
        use properties::longhands;
        use properties::property_bit_field::PropertyBitField;
        use properties::{ComputedValues, ServoComputedValues, PropertyDeclaration};
        use properties::style_struct_traits::${data.current_style_struct.trait_name};
        use properties::style_structs;
        use std::boxed::Box as StdBox;
        use std::collections::HashMap;
        use std::sync::Arc;
        use values::computed::{TContext, ToComputedValue};
        use values::{computed, specified};
        use string_cache::Atom;
        ${caller.body()}
        #[allow(unused_variables)]
        pub fn cascade_property<C: ComputedValues>(
                                declaration: &PropertyDeclaration,
                                inherited_style: &C,
                                context: &mut computed::Context<C>,
                                seen: &mut PropertyBitField,
                                cacheable: &mut bool,
                                error_reporter: &mut StdBox<ParseErrorReporter + Send>) {
            let declared_value = match *declaration {
                PropertyDeclaration::${property.camel_case}(ref declared_value) => {
                    declared_value
                }
                _ => panic!("entered the wrong cascade_property() implementation"),
            };
            % if not property.derived_from:
                if seen.get_${property.ident}() {
                    return
                }
                seen.set_${property.ident}();
                {
                    let custom_props = context.style().custom_properties();
                    ::properties::substitute_variables_${property.ident}(
                        declared_value, &custom_props, |value| match *value {
                            DeclaredValue::Value(ref specified_value) => {
                                let computed = specified_value.to_computed_value(context);
                                context.mutate_style().mutate_${data.current_style_struct.trait_name_lower}()
                                                      .set_${property.ident}(computed);
                            }
                            DeclaredValue::WithVariables { .. } => unreachable!(),
                            DeclaredValue::Initial => {
                                // We assume that it's faster to use copy_*_from rather than
                                // set_*(get_initial_value());
                                let initial_struct = C::initial_values()
                                                      .get_${data.current_style_struct.trait_name_lower}();
                                context.mutate_style().mutate_${data.current_style_struct.trait_name_lower}()
                                                      .copy_${property.ident}_from(initial_struct);
                            },
                            DeclaredValue::Inherit => {
                                // This is a bit slow, but this is rare so it shouldn't
                                // matter.
                                //
                                // FIXME: is it still?
                                *cacheable = false;
                                let inherited_struct =
                                    inherited_style.get_${data.current_style_struct.trait_name_lower}();
                                context.mutate_style().mutate_${data.current_style_struct.trait_name_lower}()
                                       .copy_${property.ident}_from(inherited_struct);
                            }
                        }, error_reporter
                    );
                }

                % if property.custom_cascade:
                    cascade_property_custom(declaration,
                                            inherited_style,
                                            context,
                                            seen,
                                            cacheable,
                                            error_reporter);
                % endif
            % else:
                // Do not allow stylesheets to set derived properties.
            % endif
        }
        % if not property.derived_from:
            pub fn parse_declared(context: &ParserContext, input: &mut Parser)
                               -> Result<DeclaredValue<SpecifiedValue>, ()> {
                match input.try(CSSWideKeyword::parse) {
                    Ok(CSSWideKeyword::InheritKeyword) => Ok(DeclaredValue::Inherit),
                    Ok(CSSWideKeyword::InitialKeyword) => Ok(DeclaredValue::Initial),
                    Ok(CSSWideKeyword::UnsetKeyword) => Ok(DeclaredValue::${
                        "Inherit" if data.current_style_struct.inherited else "Initial"}),
                    Err(()) => {
                        input.look_for_var_functions();
                        let start = input.position();
                        let specified = parse_specified(context, input);
                        if specified.is_err() {
                            while let Ok(_) = input.next() {}  // Look for var() after the error.
                        }
                        let var = input.seen_var_functions();
                        if specified.is_err() && var {
                            input.reset(start);
                            let (first_token_type, css) = try!(
                                ::custom_properties::parse_non_custom_with_var(input));
                            return Ok(DeclaredValue::WithVariables {
                                css: css.into_owned(),
                                first_token_type: first_token_type,
                                base_url: context.base_url.clone(),
                                from_shorthand: None,
                            })
                        }
                        specified
                    }
                }
            }
        % endif
    }
</%def>

<%def name="single_keyword(name, values, **kwargs)">
    <%call expr="single_keyword_computed(name, values, **kwargs)">
        use values::computed::ComputedValueAsSpecified;
        impl ComputedValueAsSpecified for SpecifiedValue {}
    </%call>
</%def>

<%def name="single_keyword_computed(name, values, **kwargs)">
    <%
        keyword_kwargs = {a: kwargs.pop(a, None) for a in [
            'gecko_constant_prefix', 'extra_gecko_values', 'extra_servo_values'
        ]}
    %>
    <%call expr="longhand(name, keyword=Keyword(name, values.split(), **keyword_kwargs), **kwargs)">
        pub use self::computed_value::T as SpecifiedValue;
        ${caller.body()}
        pub mod computed_value {
            define_css_keyword_enum! { T:
                % for value in data.longhands_by_name[name].keyword.values_for(product):
                    "${value}" => ${to_rust_ident(value)},
                % endfor
            }
        }
        #[inline] pub fn get_initial_value() -> computed_value::T {
            computed_value::T::${to_rust_ident(values.split()[0])}
        }
        pub fn parse(_context: &ParserContext, input: &mut Parser)
                     -> Result<SpecifiedValue, ()> {
            computed_value::T::parse(input)
        }
    </%call>
</%def>
<commit_msg>Make predefined_type use kwargs.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

<%! from data import Keyword, to_rust_ident %>

<%def name="longhand(name, **kwargs)">
    <%call expr="raw_longhand(name, **kwargs)">
        ${caller.body()}
        % if not data.longhands_by_name[name].derived_from:
            pub fn parse_specified(context: &ParserContext, input: &mut Parser)
                               -> Result<DeclaredValue<SpecifiedValue>, ()> {
                parse(context, input).map(DeclaredValue::Value)
            }
        % endif
    </%call>
</%def>

<%def name="predefined_type(name, type, initial_value, parse_method='parse', **kwargs)">
    <%call expr="longhand(name, **kwargs)">
        #[allow(unused_imports)]
        use app_units::Au;
        pub type SpecifiedValue = specified::${type};
        pub mod computed_value {
            pub use values::computed::${type} as T;
        }
        #[inline] pub fn get_initial_value() -> computed_value::T { ${initial_value} }
        #[inline] pub fn parse(_context: &ParserContext, input: &mut Parser)
                               -> Result<SpecifiedValue, ()> {
            specified::${type}::${parse_method}(input)
        }
    </%call>
</%def>

<%def name="raw_longhand(*args, **kwargs)">
    <%
        property = data.declare_longhand(*args, **kwargs)
        if property is None:
            return ""
    %>
    pub mod ${property.ident} {
        #![allow(unused_imports)]
        % if not property.derived_from:
            use cssparser::Parser;
            use parser::ParserContext;
            use properties::{CSSWideKeyword, DeclaredValue, Shorthand};
        % endif
        use error_reporting::ParseErrorReporter;
        use properties::longhands;
        use properties::property_bit_field::PropertyBitField;
        use properties::{ComputedValues, ServoComputedValues, PropertyDeclaration};
        use properties::style_struct_traits::${data.current_style_struct.trait_name};
        use properties::style_structs;
        use std::boxed::Box as StdBox;
        use std::collections::HashMap;
        use std::sync::Arc;
        use values::computed::{TContext, ToComputedValue};
        use values::{computed, specified};
        use string_cache::Atom;
        ${caller.body()}
        #[allow(unused_variables)]
        pub fn cascade_property<C: ComputedValues>(
                                declaration: &PropertyDeclaration,
                                inherited_style: &C,
                                context: &mut computed::Context<C>,
                                seen: &mut PropertyBitField,
                                cacheable: &mut bool,
                                error_reporter: &mut StdBox<ParseErrorReporter + Send>) {
            let declared_value = match *declaration {
                PropertyDeclaration::${property.camel_case}(ref declared_value) => {
                    declared_value
                }
                _ => panic!("entered the wrong cascade_property() implementation"),
            };
            % if not property.derived_from:
                if seen.get_${property.ident}() {
                    return
                }
                seen.set_${property.ident}();
                {
                    let custom_props = context.style().custom_properties();
                    ::properties::substitute_variables_${property.ident}(
                        declared_value, &custom_props, |value| match *value {
                            DeclaredValue::Value(ref specified_value) => {
                                let computed = specified_value.to_computed_value(context);
                                context.mutate_style().mutate_${data.current_style_struct.trait_name_lower}()
                                                      .set_${property.ident}(computed);
                            }
                            DeclaredValue::WithVariables { .. } => unreachable!(),
                            DeclaredValue::Initial => {
                                // We assume that it's faster to use copy_*_from rather than
                                // set_*(get_initial_value());
                                let initial_struct = C::initial_values()
                                                      .get_${data.current_style_struct.trait_name_lower}();
                                context.mutate_style().mutate_${data.current_style_struct.trait_name_lower}()
                                                      .copy_${property.ident}_from(initial_struct);
                            },
                            DeclaredValue::Inherit => {
                                // This is a bit slow, but this is rare so it shouldn't
                                // matter.
                                //
                                // FIXME: is it still?
                                *cacheable = false;
                                let inherited_struct =
                                    inherited_style.get_${data.current_style_struct.trait_name_lower}();
                                context.mutate_style().mutate_${data.current_style_struct.trait_name_lower}()
                                       .copy_${property.ident}_from(inherited_struct);
                            }
                        }, error_reporter
                    );
                }

                % if property.custom_cascade:
                    cascade_property_custom(declaration,
                                            inherited_style,
                                            context,
                                            seen,
                                            cacheable,
                                            error_reporter);
                % endif
            % else:
                // Do not allow stylesheets to set derived properties.
            % endif
        }
        % if not property.derived_from:
            pub fn parse_declared(context: &ParserContext, input: &mut Parser)
                               -> Result<DeclaredValue<SpecifiedValue>, ()> {
                match input.try(CSSWideKeyword::parse) {
                    Ok(CSSWideKeyword::InheritKeyword) => Ok(DeclaredValue::Inherit),
                    Ok(CSSWideKeyword::InitialKeyword) => Ok(DeclaredValue::Initial),
                    Ok(CSSWideKeyword::UnsetKeyword) => Ok(DeclaredValue::${
                        "Inherit" if data.current_style_struct.inherited else "Initial"}),
                    Err(()) => {
                        input.look_for_var_functions();
                        let start = input.position();
                        let specified = parse_specified(context, input);
                        if specified.is_err() {
                            while let Ok(_) = input.next() {}  // Look for var() after the error.
                        }
                        let var = input.seen_var_functions();
                        if specified.is_err() && var {
                            input.reset(start);
                            let (first_token_type, css) = try!(
                                ::custom_properties::parse_non_custom_with_var(input));
                            return Ok(DeclaredValue::WithVariables {
                                css: css.into_owned(),
                                first_token_type: first_token_type,
                                base_url: context.base_url.clone(),
                                from_shorthand: None,
                            })
                        }
                        specified
                    }
                }
            }
        % endif
    }
</%def>

<%def name="single_keyword(name, values, **kwargs)">
    <%call expr="single_keyword_computed(name, values, **kwargs)">
        use values::computed::ComputedValueAsSpecified;
        impl ComputedValueAsSpecified for SpecifiedValue {}
    </%call>
</%def>

<%def name="single_keyword_computed(name, values, **kwargs)">
    <%
        keyword_kwargs = {a: kwargs.pop(a, None) for a in [
            'gecko_constant_prefix', 'extra_gecko_values', 'extra_servo_values'
        ]}
    %>
    <%call expr="longhand(name, keyword=Keyword(name, values.split(), **keyword_kwargs), **kwargs)">
        pub use self::computed_value::T as SpecifiedValue;
        ${caller.body()}
        pub mod computed_value {
            define_css_keyword_enum! { T:
                % for value in data.longhands_by_name[name].keyword.values_for(product):
                    "${value}" => ${to_rust_ident(value)},
                % endfor
            }
        }
        #[inline] pub fn get_initial_value() -> computed_value::T {
            computed_value::T::${to_rust_ident(values.split()[0])}
        }
        pub fn parse(_context: &ParserContext, input: &mut Parser)
                     -> Result<SpecifiedValue, ()> {
            computed_value::T::parse(input)
        }
    </%call>
</%def>
<|endoftext|>


<commit_before>use rustc::lint::*;
use rustc::{declare_lint, lint_array};
use syntax::ast::*;
use syntax::tokenstream::{ThinTokenStream, TokenStream};
use syntax::parse::{token, parser};
use crate::utils::{span_lint, span_lint_and_sugg};

/// **What it does:** This lint warns when you use `println!("")` to
/// print a newline.
///
/// **Why is this bad?** You should use `println!()`, which is simpler.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// println!("");
/// ```
declare_clippy_lint! {
    pub PRINTLN_EMPTY_STRING,
    style,
    "using `println!(\"\")` with an empty string"
}

/// **What it does:** This lint warns when you use `print!()` with a format
/// string that
/// ends in a newline.
///
/// **Why is this bad?** You should use `println!()` instead, which appends the
/// newline.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// print!("Hello {}!\n", name);
/// ```
/// use println!() instead
/// ```rust
/// println!("Hello {}!", name);
/// ```
declare_clippy_lint! {
    pub PRINT_WITH_NEWLINE,
    style,
    "using `print!()` with a format string that ends in a single newline"
}

/// **What it does:** Checks for printing on *stdout*. The purpose of this lint
/// is to catch debugging remnants.
///
/// **Why is this bad?** People often print on *stdout* while debugging an
/// application and might forget to remove those prints afterward.
///
/// **Known problems:** Only catches `print!` and `println!` calls.
///
/// **Example:**
/// ```rust
/// println!("Hello world!");
/// ```
declare_clippy_lint! {
    pub PRINT_STDOUT,
    restriction,
    "printing on stdout"
}

/// **What it does:** Checks for use of `Debug` formatting. The purpose of this
/// lint is to catch debugging remnants.
///
/// **Why is this bad?** The purpose of the `Debug` trait is to facilitate
/// debugging Rust code. It should not be used in in user-facing output.
///
/// **Example:**
/// ```rust
/// println!("{:?}", foo);
/// ```
declare_clippy_lint! {
    pub USE_DEBUG,
    restriction,
    "use of `Debug`-based formatting"
}

/// **What it does:** This lint warns about the use of literals as `print!`/`println!` args.
///
/// **Why is this bad?** Using literals as `println!` args is inefficient
/// (c.f., https://github.com/matthiaskrgr/rust-str-bench) and unnecessary
/// (i.e., just put the literal in the format string)
///
/// **Known problems:** Will also warn with macro calls as arguments that expand to literals
/// -- e.g., `println!("{}", env!("FOO"))`.
///
/// **Example:**
/// ```rust
/// println!("{}", "foo");
/// ```
/// use the literal without formatting:
/// ```rust
/// println!("foo");
/// ```
declare_clippy_lint! {
    pub PRINT_LITERAL,
    style,
    "printing a literal with a format string"
}

/// **What it does:** This lint warns when you use `writeln!(buf, "")` to
/// print a newline.
///
/// **Why is this bad?** You should use `writeln!(buf)`, which is simpler.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// writeln!("");
/// ```
declare_clippy_lint! {
    pub WRITELN_EMPTY_STRING,
    style,
    "using `writeln!(\"\")` with an empty string"
}

/// **What it does:** This lint warns when you use `write!()` with a format
/// string that
/// ends in a newline.
///
/// **Why is this bad?** You should use `writeln!()` instead, which appends the
/// newline.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// write!(buf, "Hello {}!\n", name);
/// ```
declare_clippy_lint! {
    pub WRITE_WITH_NEWLINE,
    style,
    "using `write!()` with a format string that ends in a single newline"
}

/// **What it does:** This lint warns about the use of literals as `write!`/`writeln!` args.
///
/// **Why is this bad?** Using literals as `writeln!` args is inefficient
/// (c.f., https://github.com/matthiaskrgr/rust-str-bench) and unnecessary
/// (i.e., just put the literal in the format string)
///
/// **Known problems:** Will also warn with macro calls as arguments that expand to literals
/// -- e.g., `writeln!(buf, "{}", env!("FOO"))`.
///
/// **Example:**
/// ```rust
/// writeln!(buf, "{}", "foo");
/// ```
declare_clippy_lint! {
    pub WRITE_LITERAL,
    style,
    "writing a literal with a format string"
}

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

impl LintPass for Pass {
    fn get_lints(&self) -> LintArray {
        lint_array!(
            PRINT_WITH_NEWLINE,
            PRINTLN_EMPTY_STRING,
            PRINT_STDOUT,
            USE_DEBUG,
            PRINT_LITERAL,
            WRITE_WITH_NEWLINE,
            WRITELN_EMPTY_STRING,
            WRITE_LITERAL
        )
    }
}

impl EarlyLintPass for Pass {
    fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &Mac) {
        if mac.node.path == "println" {
            span_lint(cx, PRINT_STDOUT, mac.span, "use of `println!`");
            if let Some(fmtstr) = check_tts(cx, &mac.node.tts, false) {
                if fmtstr == "" {
                    span_lint_and_sugg(
                        cx,
                        PRINTLN_EMPTY_STRING,
                        mac.span,
                        "using `println!(\"\")`",
                        "replace it with",
                        "println!()".to_string(),
                    );
                }
            }
        } else if mac.node.path == "print" {
            span_lint(cx, PRINT_STDOUT, mac.span, "use of `print!`");
            if let Some(fmtstr) = check_tts(cx, &mac.node.tts, false) {
                if fmtstr.ends_with("\\n") && !fmtstr.ends_with("\\n\\n") {
                    span_lint(cx, PRINT_WITH_NEWLINE, mac.span,
                            "using `print!()` with a format string that ends in a \
                            single newline, consider using `println!()` instead");
                }
            }
        } else if mac.node.path == "write" {
            if let Some(fmtstr) = check_tts(cx, &mac.node.tts, true) {
                if fmtstr.ends_with("\\n") && !fmtstr.ends_with("\\n\\n") {
                    span_lint(cx, WRITE_WITH_NEWLINE, mac.span,
                            "using `write!()` with a format string that ends in a \
                            single newline, consider using `writeln!()` instead");
                }
            }
        } else if mac.node.path == "writeln" {
            if let Some(fmtstr) = check_tts(cx, &mac.node.tts, true) {
                if fmtstr == "" {
                    span_lint_and_sugg(
                        cx,
                        WRITELN_EMPTY_STRING,
                        mac.span,
                        "using `writeln!(v, \"\")`",
                        "replace it with",
                        "writeln!(v)".to_string(),
                    );
                }
            }
        }
    }
}

fn check_tts<'a>(cx: &EarlyContext<'a>, tts: &ThinTokenStream, is_write: bool) -> Option<String> {
    let tts = TokenStream::from(tts.clone());
    let mut parser = parser::Parser::new(
        &cx.sess.parse_sess,
        tts,
        None,
        false,
        false,
    );
    if is_write {
        // skip the initial write target
        parser.parse_expr().map_err(|mut err| err.cancel()).ok()?;
        // might be `writeln!(foo)`
        parser.expect(&token::Comma).map_err(|mut err| err.cancel()).ok()?;
    }
    let fmtstr = parser.parse_str().map_err(|mut err| err.cancel()).ok()?.0.to_string();
    use fmt_macros::*;
    let tmp = fmtstr.clone();
    let mut args = vec![];
    let mut fmt_parser = Parser::new(&tmp, None);
    while let Some(piece) = fmt_parser.next() {
        if !fmt_parser.errors.is_empty() {
            return None;
        }
        if let Piece::NextArgument(arg) = piece {
            if arg.format.ty == "?" {
                // FIXME: modify rustc's fmt string parser to give us the current span
                span_lint(cx, USE_DEBUG, parser.prev_span, "use of `Debug`-based formatting");
            }
            args.push(arg);
        }
    }
    let lint = if is_write {
        WRITE_LITERAL
    } else {
        PRINT_LITERAL
    };
    let mut idx = 0;
    loop {
        if !parser.eat(&token::Comma) {
            assert!(parser.eat(&token::Eof));
            return Some(fmtstr);
        }
        let expr = parser.parse_expr().map_err(|mut err| err.cancel()).ok()?;
        const SIMPLE: FormatSpec<'_> = FormatSpec {
            fill: None,
            align: AlignUnknown,
            flags: 0,
            precision: CountImplied,
            width: CountImplied,
            ty: "",
        };
        match &expr.node {
            ExprKind::Lit(_) => {
                let mut all_simple = true;
                let mut seen = false;
                for arg in &args {
                    match arg.position {
                        | ArgumentImplicitlyIs(n)
                        | ArgumentIs(n)
                        => if n == idx {
                            all_simple &= arg.format == SIMPLE;
                            seen = true;
                        },
                        ArgumentNamed(_) => {},
                    }
                }
                if all_simple && seen {
                    span_lint(cx, lint, expr.span, "literal with an empty format string");
                }
                idx += 1;
            },
            ExprKind::Assign(lhs, rhs) => {
                if let ExprKind::Lit(_) = rhs.node {
                    if let ExprKind::Path(_, p) = &lhs.node {
                        let mut all_simple = true;
                        let mut seen = false;
                        for arg in &args {
                            match arg.position {
                                | ArgumentImplicitlyIs(_)
                                | ArgumentIs(_)
                                => {},
                                ArgumentNamed(name) => if *p == name {
                                    seen = true;
                                    all_simple &= arg.format == SIMPLE;
                                },
                            }
                        }
                        if all_simple && seen {
                            span_lint(cx, lint, rhs.span, "literal with an empty format string");
                        }
                    }
                }
            },
            _ => idx += 1,
        }
    }
}
<commit_msg>WIP of #3016 for hardocded suggestion for writeln on empty string<commit_after>use rustc::lint::*;
use rustc::{declare_lint, lint_array};
use syntax::ast::*;
use syntax::tokenstream::{ThinTokenStream, TokenStream};
use syntax::parse::{token, parser};
use crate::utils::{span_lint, span_lint_and_sugg};

/// **What it does:** This lint warns when you use `println!("")` to
/// print a newline.
///
/// **Why is this bad?** You should use `println!()`, which is simpler.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// println!("");
/// ```
declare_clippy_lint! {
    pub PRINTLN_EMPTY_STRING,
    style,
    "using `println!(\"\")` with an empty string"
}

/// **What it does:** This lint warns when you use `print!()` with a format
/// string that
/// ends in a newline.
///
/// **Why is this bad?** You should use `println!()` instead, which appends the
/// newline.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// print!("Hello {}!\n", name);
/// ```
/// use println!() instead
/// ```rust
/// println!("Hello {}!", name);
/// ```
declare_clippy_lint! {
    pub PRINT_WITH_NEWLINE,
    style,
    "using `print!()` with a format string that ends in a single newline"
}

/// **What it does:** Checks for printing on *stdout*. The purpose of this lint
/// is to catch debugging remnants.
///
/// **Why is this bad?** People often print on *stdout* while debugging an
/// application and might forget to remove those prints afterward.
///
/// **Known problems:** Only catches `print!` and `println!` calls.
///
/// **Example:**
/// ```rust
/// println!("Hello world!");
/// ```
declare_clippy_lint! {
    pub PRINT_STDOUT,
    restriction,
    "printing on stdout"
}

/// **What it does:** Checks for use of `Debug` formatting. The purpose of this
/// lint is to catch debugging remnants.
///
/// **Why is this bad?** The purpose of the `Debug` trait is to facilitate
/// debugging Rust code. It should not be used in in user-facing output.
///
/// **Example:**
/// ```rust
/// println!("{:?}", foo);
/// ```
declare_clippy_lint! {
    pub USE_DEBUG,
    restriction,
    "use of `Debug`-based formatting"
}

/// **What it does:** This lint warns about the use of literals as `print!`/`println!` args.
///
/// **Why is this bad?** Using literals as `println!` args is inefficient
/// (c.f., https://github.com/matthiaskrgr/rust-str-bench) and unnecessary
/// (i.e., just put the literal in the format string)
///
/// **Known problems:** Will also warn with macro calls as arguments that expand to literals
/// -- e.g., `println!("{}", env!("FOO"))`.
///
/// **Example:**
/// ```rust
/// println!("{}", "foo");
/// ```
/// use the literal without formatting:
/// ```rust
/// println!("foo");
/// ```
declare_clippy_lint! {
    pub PRINT_LITERAL,
    style,
    "printing a literal with a format string"
}

/// **What it does:** This lint warns when you use `writeln!(buf, "")` to
/// print a newline.
///
/// **Why is this bad?** You should use `writeln!(buf)`, which is simpler.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// writeln!("");
/// ```
declare_clippy_lint! {
    pub WRITELN_EMPTY_STRING,
    style,
    "using `writeln!(\"\")` with an empty string"
}

/// **What it does:** This lint warns when you use `write!()` with a format
/// string that
/// ends in a newline.
///
/// **Why is this bad?** You should use `writeln!()` instead, which appends the
/// newline.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// write!(buf, "Hello {}!\n", name);
/// ```
declare_clippy_lint! {
    pub WRITE_WITH_NEWLINE,
    style,
    "using `write!()` with a format string that ends in a single newline"
}

/// **What it does:** This lint warns about the use of literals as `write!`/`writeln!` args.
///
/// **Why is this bad?** Using literals as `writeln!` args is inefficient
/// (c.f., https://github.com/matthiaskrgr/rust-str-bench) and unnecessary
/// (i.e., just put the literal in the format string)
///
/// **Known problems:** Will also warn with macro calls as arguments that expand to literals
/// -- e.g., `writeln!(buf, "{}", env!("FOO"))`.
///
/// **Example:**
/// ```rust
/// writeln!(buf, "{}", "foo");
/// ```
declare_clippy_lint! {
    pub WRITE_LITERAL,
    style,
    "writing a literal with a format string"
}

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

impl LintPass for Pass {
    fn get_lints(&self) -> LintArray {
        lint_array!(
            PRINT_WITH_NEWLINE,
            PRINTLN_EMPTY_STRING,
            PRINT_STDOUT,
            USE_DEBUG,
            PRINT_LITERAL,
            WRITE_WITH_NEWLINE,
            WRITELN_EMPTY_STRING,
            WRITE_LITERAL
        )
    }
}

impl EarlyLintPass for Pass {
    fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &Mac) {
        if mac.node.path == "println" {
            span_lint(cx, PRINT_STDOUT, mac.span, "use of `println!`");
            if let Some(fmtstr) = check_tts(cx, &mac.node.tts, false).0 {
                if fmtstr == "" {
                    span_lint_and_sugg(
                        cx,
                        PRINTLN_EMPTY_STRING,
                        mac.span,
                        "using `println!(\"\")`",
                        "replace it with",
                        "println!()".to_string(),
                    );
                }
            }
        } else if mac.node.path == "print" {
            span_lint(cx, PRINT_STDOUT, mac.span, "use of `print!`");
            if let Some(fmtstr) = check_tts(cx, &mac.node.tts, false).0 {
                if fmtstr.ends_with("\\n") && !fmtstr.ends_with("\\n\\n") {
                    span_lint(cx, PRINT_WITH_NEWLINE, mac.span,
                            "using `print!()` with a format string that ends in a \
                            single newline, consider using `println!()` instead");
                }
            }
        } else if mac.node.path == "write" {
            if let Some(fmtstr) = check_tts(cx, &mac.node.tts, true).0 {
                if fmtstr.ends_with("\\n") && !fmtstr.ends_with("\\n\\n") {
                    span_lint(cx, WRITE_WITH_NEWLINE, mac.span,
                            "using `write!()` with a format string that ends in a \
                            single newline, consider using `writeln!()` instead");
                }
            }
        } else if mac.node.path == "writeln" {
            let check_tts = check_tts(cx, &mac.node.tts, true);
            if let Some(fmtstr) = check_tts.0 {
                if fmtstr == "" {
                    span_lint_and_sugg(
                        cx,
                        WRITELN_EMPTY_STRING,
                        mac.span,
                        format!("using `writeln!({}, \"\")`", check_tts.1).as_str(),
                        "replace it with",
                        format!("using `writeln!({})`", check_tts.1),
                    );
                }
            }
        }
    }
}

fn check_tts<'a>(cx: &EarlyContext<'a>, tts: &ThinTokenStream, is_write: bool) -> (Option<String>, Option<Expr>) {
    let tts = TokenStream::from(tts.clone());
    let mut parser = parser::Parser::new(
        &cx.sess.parse_sess,
        tts,
        None,
        false,
        false,
    );
    // skip the initial write target
    let expr: Option<Expr> = match parser.parse_expr().map_err(|mut err| err.cancel()).ok() {
        Some(p) => Some(p.into_vec().0),
        None => None,
    };
    // might be `writeln!(foo)`
    parser.expect(&token::Comma).map_err(|mut err| err.cancel()).ok()?;

    let fmtstr = parser.parse_str().map_err(|mut err| err.cancel()).ok()?.0.to_string();
    use fmt_macros::*;
    let tmp = fmtstr.clone();
    let mut args = vec![];
    let mut fmt_parser = Parser::new(&tmp, None);
    while let Some(piece) = fmt_parser.next() {
        if !fmt_parser.errors.is_empty() {
            return (None, expr);
        }
        if let Piece::NextArgument(arg) = piece {
            if arg.format.ty == "?" {
                // FIXME: modify rustc's fmt string parser to give us the current span
                span_lint(cx, USE_DEBUG, parser.prev_span, "use of `Debug`-based formatting");
            }
            args.push(arg);
        }
    }
    let lint = if is_write {
        WRITE_LITERAL
    } else {
        PRINT_LITERAL
    };
    let mut idx = 0;
    loop {
        if !parser.eat(&token::Comma) {
            assert!(parser.eat(&token::Eof));
            return (Some(fmtstr), expr);
        }
        let expr = parser.parse_expr().map_err(|mut err| err.cancel()).ok()?;
        const SIMPLE: FormatSpec<'_> = FormatSpec {
            fill: None,
            align: AlignUnknown,
            flags: 0,
            precision: CountImplied,
            width: CountImplied,
            ty: "",
        };
        match &expr.node {
            ExprKind::Lit(_) => {
                let mut all_simple = true;
                let mut seen = false;
                for arg in &args {
                    match arg.position {
                        | ArgumentImplicitlyIs(n)
                        | ArgumentIs(n)
                        => if n == idx {
                            all_simple &= arg.format == SIMPLE;
                            seen = true;
                        },
                        ArgumentNamed(_) => {},
                    }
                }
                if all_simple && seen {
                    span_lint(cx, lint, expr.span, "literal with an empty format string");
                }
                idx += 1;
            },
            ExprKind::Assign(lhs, rhs) => {
                if let ExprKind::Lit(_) = rhs.node {
                    if let ExprKind::Path(_, p) = &lhs.node {
                        let mut all_simple = true;
                        let mut seen = false;
                        for arg in &args {
                            match arg.position {
                                | ArgumentImplicitlyIs(_)
                                | ArgumentIs(_)
                                => {},
                                ArgumentNamed(name) => if *p == name {
                                    seen = true;
                                    all_simple &= arg.format == SIMPLE;
                                },
                            }
                        }
                        if all_simple && seen {
                            span_lint(cx, lint, rhs.span, "literal with an empty format string");
                        }
                    }
                }
            },
            _ => idx += 1,
        }
    }
}
<|endoftext|>


<commit_before>#![feature(plugin)]
#![plugin(clippy)]

#[deny(cast_precision_loss, cast_possible_truncation, cast_sign_loss)]
#[allow(dead_code)]
fn main() {
    let i : i32 = 42;
    let u : u32 = 42;
    let f : f32 = 42.0;

    // Test cast_precision_loss
    i as f32; //~ERROR converting from i32 to f32, which causes a loss of precision (i32 is 32 bits wide, but f32's mantissa is only 23 bits wide)
    (i as i64) as f32; //~ERROR converting from i64 to f32, which causes a loss of precision (i64 is 64 bits wide, but f32's mantissa is only 23 bits wide)
    (i as i64) as f64; //~ERROR converting from i64 to f64, which causes a loss of precision (i64 is 64 bits wide, but f64's mantissa is only 52 bits wide)
    u as f32; //~ERROR converting from u32 to f32, which causes a loss of precision (u32 is 32 bits wide, but f32's mantissa is only 23 bits wide)
    (u as u64) as f32; //~ERROR converting from u64 to f32, which causes a loss of precision (u64 is 64 bits wide, but f32's mantissa is only 23 bits wide)
    (u as u64) as f64; //~ERROR converting from u64 to f64, which causes a loss of precision (u64 is 64 bits wide, but f64's mantissa is only 52 bits wide)
    i as f64; // Should not trigger the lint
    u as f64; // Should not trigger the lint

    // Test cast_possible_truncation
    f as i32; //~ERROR casting f32 to i32 may cause truncation of the value
    f as u32; //~ERROR casting f32 to u32 may cause truncation of the value
              //~^ERROR casting from f32 to u32 loses the sign of the value
    i as u8;  //~ERROR casting i32 to u8 may cause truncation of the value
              //~^ERROR casting from i32 to u8 loses the sign of the value
    (f as f64) as f32; //~ERROR casting f64 to f32 may cause truncation of the value
    i as i8;  //~ERROR casting i32 to i8 may cause truncation of the value
    u as i32; //~ERROR casting u32 to i32 may cause truncation of the value

    // Test cast_sign_loss
    i as u32; //~ERROR casting from i32 to u32 loses the sign of the value

    // Extra checks for usize/isize
    /*
    let is : isize = -42;
    let us : usize = 42;
    is as usize; //ERROR casting from isize to usize loses the sign of the value
    is as i8; //ERROR casting isize to i8 may cause truncation of the value
    is as f64; //ERROR converting from isize to f64, which causes a loss of precision on 64-bit architectures (isize is 64 bits wide, but f64's mantissa is only 52 bits wide)
    us as f64; //ERROR converting from usize to f64, which causes a loss of precision on 64-bit architectures (usize is 64 bits wide, but f64's mantissa is only 52 bits wide)
    */
}<commit_msg>Updated test case for cast lints.<commit_after>#![feature(plugin)]
#![plugin(clippy)]

#[deny(cast_precision_loss, cast_possible_truncation, cast_sign_loss, cast_possible_wrap)]
fn main() {
    // Test cast_precision_loss
    1i32 as f32; //~ERROR casting i32 to f32 causes a loss of precision (i32 is 32 bits wide, but f32's mantissa is only 23 bits wide)
    1i64 as f32; //~ERROR casting i64 to f32 causes a loss of precision (i64 is 64 bits wide, but f32's mantissa is only 23 bits wide)
    1i64 as f64; //~ERROR casting i64 to f64 causes a loss of precision (i64 is 64 bits wide, but f64's mantissa is only 52 bits wide)
    1u32 as f32; //~ERROR casting u32 to f32 causes a loss of precision (u32 is 32 bits wide, but f32's mantissa is only 23 bits wide)
    1u64 as f32; //~ERROR casting u64 to f32 causes a loss of precision (u64 is 64 bits wide, but f32's mantissa is only 23 bits wide)
    1u64 as f64; //~ERROR casting u64 to f64 causes a loss of precision (u64 is 64 bits wide, but f64's mantissa is only 52 bits wide)
    1i32 as f64; // Should not trigger the lint
    1u32 as f64; // Should not trigger the lint

    // Test cast_possible_truncation
    1f32 as i32;   //~ERROR casting f32 to i32 may truncate the value
    1f32 as u32;   //~ERROR casting f32 to u32 may truncate the value
                  //~^ERROR casting f32 to u32 may lose the sign of the value
    1f64 as f32;   //~ERROR casting f64 to f32 may truncate the value
    1i32 as i8;    //~ERROR casting i32 to i8 may truncate the value
    1i32 as u8;    //~ERROR casting i32 to u8 may truncate the value
                  //~^ERROR casting i32 to u8 may lose the sign of the value
    1f64 as isize; //~ERROR casting f64 to isize may truncate the value
    1f64 as usize; //~ERROR casting f64 to usize may truncate the value
                  //~^ERROR casting f64 to usize may lose the sign of the value

    // Test cast_possible_wrap
    1u8 as i8;       //~ERROR casting u8 to i8 may wrap around the value
    1u16 as i16;     //~ERROR casting u16 to i16 may wrap around the value
    1u32 as i32;     //~ERROR casting u32 to i32 may wrap around the value
    1u64 as i64;     //~ERROR casting u64 to i64 may wrap around the value
    1usize as isize; //~ERROR casting usize to isize may wrap around the value

    // Test cast_sign_loss
    1i32 as u32;     //~ERROR casting i32 to u32 may lose the sign of the value
    1isize as usize; //~ERROR casting isize to usize may lose the sign of the value

    // Extra checks for *size
    // Casting from *size
    1isize as i8;  //~ERROR casting isize to i8 may truncate the value
    1isize as f64; //~ERROR casting isize to f64 causes a loss of precision on targets with 64-bit wide pointers (isize is 64 bits wide, but f64's mantissa is only 52 bits wide)
    1usize as f64; //~ERROR casting usize to f64 causes a loss of precision on targets with 64-bit wide pointers (usize is 64 bits wide, but f64's mantissa is only 52 bits wide)
    1isize as f32; //~ERROR casting isize to f32 causes a loss of precision (isize is 32 or 64 bits wide, but f32's mantissa is only 23 bits wide)
    1usize as f32; //~ERROR casting usize to f32 causes a loss of precision (usize is 32 or 64 bits wide, but f32's mantissa is only 23 bits wide)
    1isize as i32; //~ERROR casting isize to i32 may truncate the value on targets with 64-bit wide pointers
    1isize as u32; //~ERROR casting isize to u32 may lose the sign of the value
                  //~^ERROR casting isize to u32 may truncate the value on targets with 64-bit wide pointers
    1usize as u32; //~ERROR casting usize to u32 may truncate the value on targets with 64-bit wide pointers
    // Casting to *size
    1i64 as isize; //~ERROR casting i64 to isize may truncate the value on targets with 32-bit wide pointers
    1i64 as usize; //~ERROR casting i64 to usize may truncate the value on targets with 32-bit wide pointers
                  //~^ERROR casting i64 to usize may lose the sign of the value
    1u64 as isize; //~ERROR casting u64 to isize may truncate the value on targets with 32-bit wide pointers
                  //~^ERROR casting u64 to isize may wrap around the value on targets with 64-bit wide pointers
    1u64 as usize; //~ERROR casting u64 to usize may truncate the value on targets with 32-bit wide pointers
}<|endoftext|>


<commit_before>//! Note
//! ----
//! You're probably viewing this file because you're adding a test (or you might
//! just be browsing, in that case, hey there!).
//!
//! The iter test suite is split into two big modules, and some miscellaneous
//! smaller modules. The two big modules are `adapters` and `traits`.
//!
//! `adapters` are for methods on `Iterator` that adapt the data inside the
//! iterator, whether it be by emitting another iterator or returning an item
//! from inside the iterator after executing a closure on each item.
//!
//! `traits` are for trait's that extend an `Iterator` (and the `Iterator`
//! trait itself, mostly containing miscellaneous methods). For the most part,
//! if a test in `traits` uses a specific adapter, then it should be moved to
//! that adapter's test file in `adapters`.

mod adapters;
mod range;
mod sources;
mod traits;

use core::cell::Cell;
use core::convert::TryFrom;
use core::iter::*;

pub fn is_trusted_len<I: TrustedLen>(_: I) {}

#[test]
fn test_multi_iter() {
    let xs = [1, 2, 3, 4];
    let ys = [4, 3, 2, 1];
    assert!(xs.iter().eq(ys.iter().rev()));
    assert!(xs.iter().lt(xs.iter().skip(2)));
}

#[test]
fn test_counter_from_iter() {
    let it = (0..).step_by(5).take(10);
    let xs: Vec<isize> = FromIterator::from_iter(it);
    assert_eq!(xs, [0, 5, 10, 15, 20, 25, 30, 35, 40, 45]);
}

#[test]
fn test_functor_laws() {
    // identity:
    fn identity<T>(x: T) -> T {
        x
    }
    assert_eq!((0..10).map(identity).sum::<usize>(), (0..10).sum());

    // composition:
    fn f(x: usize) -> usize {
        x + 3
    }
    fn g(x: usize) -> usize {
        x * 2
    }
    fn h(x: usize) -> usize {
        g(f(x))
    }
    assert_eq!((0..10).map(f).map(g).sum::<usize>(), (0..10).map(h).sum());
}

#[test]
fn test_monad_laws_left_identity() {
    fn f(x: usize) -> impl Iterator<Item = usize> {
        (0..10).map(move |y| x * y)
    }
    assert_eq!(once(42).flat_map(f.clone()).sum::<usize>(), f(42).sum());
}

#[test]
fn test_monad_laws_right_identity() {
    assert_eq!((0..10).flat_map(|x| once(x)).sum::<usize>(), (0..10).sum());
}

#[test]
fn test_monad_laws_associativity() {
    fn f(x: usize) -> impl Iterator<Item = usize> {
        0..x
    }
    fn g(x: usize) -> impl Iterator<Item = usize> {
        (0..x).rev()
    }
    assert_eq!(
        (0..10).flat_map(f).flat_map(g).sum::<usize>(),
        (0..10).flat_map(|x| f(x).flat_map(g)).sum::<usize>()
    );
}

#[test]
pub fn extend_for_unit() {
    let mut x = 0;
    {
        let iter = (0..5).map(|_| {
            x += 1;
        });
        ().extend(iter);
    }
    assert_eq!(x, 5);
}
<commit_msg>Add test for inplace collection of Result<Vec<_>,_><commit_after>//! Note
//! ----
//! You're probably viewing this file because you're adding a test (or you might
//! just be browsing, in that case, hey there!).
//!
//! The iter test suite is split into two big modules, and some miscellaneous
//! smaller modules. The two big modules are `adapters` and `traits`.
//!
//! `adapters` are for methods on `Iterator` that adapt the data inside the
//! iterator, whether it be by emitting another iterator or returning an item
//! from inside the iterator after executing a closure on each item.
//!
//! `traits` are for trait's that extend an `Iterator` (and the `Iterator`
//! trait itself, mostly containing miscellaneous methods). For the most part,
//! if a test in `traits` uses a specific adapter, then it should be moved to
//! that adapter's test file in `adapters`.

mod adapters;
mod range;
mod sources;
mod traits;

use core::cell::Cell;
use core::convert::TryFrom;
use core::iter::*;

pub fn is_trusted_len<I: TrustedLen>(_: I) {}

#[test]
fn test_multi_iter() {
    let xs = [1, 2, 3, 4];
    let ys = [4, 3, 2, 1];
    assert!(xs.iter().eq(ys.iter().rev()));
    assert!(xs.iter().lt(xs.iter().skip(2)));
}

#[test]
fn test_counter_from_iter() {
    let it = (0..).step_by(5).take(10);
    let xs: Vec<isize> = FromIterator::from_iter(it);
    assert_eq!(xs, [0, 5, 10, 15, 20, 25, 30, 35, 40, 45]);
}

#[test]
fn test_functor_laws() {
    // identity:
    fn identity<T>(x: T) -> T {
        x
    }
    assert_eq!((0..10).map(identity).sum::<usize>(), (0..10).sum());

    // composition:
    fn f(x: usize) -> usize {
        x + 3
    }
    fn g(x: usize) -> usize {
        x * 2
    }
    fn h(x: usize) -> usize {
        g(f(x))
    }
    assert_eq!((0..10).map(f).map(g).sum::<usize>(), (0..10).map(h).sum());
}

#[test]
fn test_monad_laws_left_identity() {
    fn f(x: usize) -> impl Iterator<Item = usize> {
        (0..10).map(move |y| x * y)
    }
    assert_eq!(once(42).flat_map(f.clone()).sum::<usize>(), f(42).sum());
}

#[test]
fn test_monad_laws_right_identity() {
    assert_eq!((0..10).flat_map(|x| once(x)).sum::<usize>(), (0..10).sum());
}

#[test]
fn test_monad_laws_associativity() {
    fn f(x: usize) -> impl Iterator<Item = usize> {
        0..x
    }
    fn g(x: usize) -> impl Iterator<Item = usize> {
        (0..x).rev()
    }
    assert_eq!(
        (0..10).flat_map(f).flat_map(g).sum::<usize>(),
        (0..10).flat_map(|x| f(x).flat_map(g)).sum::<usize>()
    );
}

#[test]
pub fn extend_for_unit() {
    let mut x = 0;
    {
        let iter = (0..5).map(|_| {
            x += 1;
        });
        ().extend(iter);
    }
    assert_eq!(x, 5);
}

#[test]
pub fn inplace_result_collect() {
    let src = vec![0usize; 256];
    let srcptr = src.as_ptr();
    let sink = src.into_iter().map(|i| Ok(i)).collect::<Result<Vec<_>, ()>>().unwrap();
    let sinkptr = sink.as_ptr();
    assert_eq!(srcptr, sinkptr);

    let src: Vec<usize> = vec![0usize; 256];
    let srcptr = src.as_ptr();
    let iter = src
        .into_iter()
        .enumerate()
        .map(|i| i.0 + i.1)
        .zip(std::iter::repeat(1usize))
        .map(|(a, b)| a + b)
        .map_while(Option::Some)
        .peekable()
        .skip(1)
        .map(|e| std::num::NonZeroUsize::new(e))
        .map(|z| z.map(|u| u.get()).ok_or(()));
    let sink = iter.collect::<Result<Vec<_>, _>>().unwrap();
    let sinkptr = sink.as_ptr();
    assert_eq!(srcptr, sinkptr as *const usize);
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! `NonZero*` types that are either `core::nonzero::NonZero<_>`
//! or some stable types with an equivalent API (but no memory layout optimization).

#![cfg_attr(feature = "unstable", feature(nonzero))]
#![cfg_attr(feature = "unstable", feature(const_fn))]
#![cfg_attr(feature = "unstable", feature(const_nonzero_new))]

#[macro_use]
extern crate serde;

pub use imp::*;

#[cfg(feature = "unstable")]
mod imp {
    extern crate core;
    use self::core::nonzero::NonZero;

    #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
    pub struct NonZeroU32(NonZero<u32>);

    #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
    pub struct NonZeroUsize(NonZero<usize>);

    impl NonZeroU32 {
        #[inline] pub const unsafe fn new_unchecked(x: u32) -> Self { NonZeroU32(NonZero::new_unchecked(x)) }
        #[inline] pub fn new(x: u32) -> Option<Self> { NonZero::new(x).map(NonZeroU32) }
        #[inline] pub fn get(self) -> u32 { self.0.get() }
    }

    impl NonZeroUsize {
        #[inline] pub const unsafe fn new_unchecked(x: usize) -> Self { NonZeroUsize(NonZero::new_unchecked(x)) }
        #[inline] pub fn new(x: usize) -> Option<Self> { NonZero::new(x).map(NonZeroUsize) }
        #[inline] pub fn get(self) -> usize { self.0.get() }
    }
}

#[cfg(not(feature = "unstable"))]
mod imp {
    use std::cmp;
    use std::hash;

    #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
    pub struct NonZeroU32(u32);

    impl NonZeroU32 {
        #[inline]
        pub fn new(x: u32) -> Option<Self> {
            if x != 0 {
                Some(NonZeroU32(x))
            } else {
                None
            }
        }

        #[inline]
        pub unsafe fn new_unchecked(x: u32) -> Self {
            NonZeroU32(x)
        }

        #[inline]
        pub fn get(self) -> u32 {
            self.0
        }
    }

    #[derive(Clone, Copy, Debug, Eq)]
    pub struct NonZeroUsize(&'static ());

    impl NonZeroUsize {
        #[inline]
        pub fn new(x: usize) -> Option<Self> {
            if x != 0 {
                Some(unsafe { Self::new_unchecked(x) })
            } else {
                None
            }
        }

        #[inline]
        pub unsafe fn new_unchecked(x: usize) -> Self {
            NonZeroUsize(&*(x as *const ()))
        }

        #[inline]
        pub fn get(self) -> usize {
            self.0 as *const () as usize
        }
    }

    impl PartialEq for NonZeroUsize {
        #[inline]
        fn eq(&self, other: &Self) -> bool {
            self.get() == other.get()
        }
    }

    impl PartialOrd for NonZeroUsize {
        #[inline]
        fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
            self.get().partial_cmp(&other.get())
        }
    }

    impl Ord for NonZeroUsize {
        #[inline]
        fn cmp(&self, other: &Self) -> cmp::Ordering {
            self.get().cmp(&other.get())
        }
    }

    impl hash::Hash for NonZeroUsize {
        #[inline]
        fn hash<H: hash::Hasher>(&self, hasher: &mut H) {
            self.get().hash(hasher)
        }
    }
}
<commit_msg>Give up on NonZeroUsize memory layout optimization with unstable features.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! `NonZero*` types that are either `core::nonzero::NonZero<_>`
//! or some stable types with an equivalent API (but no memory layout optimization).

#![cfg_attr(feature = "unstable", feature(nonzero))]
#![cfg_attr(feature = "unstable", feature(const_fn))]
#![cfg_attr(feature = "unstable", feature(const_nonzero_new))]

#[macro_use]
extern crate serde;

pub use imp::*;

#[cfg(feature = "unstable")]
mod imp {
    extern crate core;
    use self::core::nonzero::NonZero;

    #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
    pub struct NonZeroU32(NonZero<u32>);

    #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
    pub struct NonZeroUsize(NonZero<usize>);

    impl NonZeroU32 {
        #[inline] pub const unsafe fn new_unchecked(x: u32) -> Self { NonZeroU32(NonZero::new_unchecked(x)) }
        #[inline] pub fn new(x: u32) -> Option<Self> { NonZero::new(x).map(NonZeroU32) }
        #[inline] pub fn get(self) -> u32 { self.0.get() }
    }

    impl NonZeroUsize {
        #[inline] pub const unsafe fn new_unchecked(x: usize) -> Self { NonZeroUsize(NonZero::new_unchecked(x)) }
        #[inline] pub fn new(x: usize) -> Option<Self> { NonZero::new(x).map(NonZeroUsize) }
        #[inline] pub fn get(self) -> usize { self.0.get() }
    }
}

#[cfg(not(feature = "unstable"))]
mod imp {
    #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
    pub struct NonZeroU32(u32);

    impl NonZeroU32 {
        #[inline]
        pub fn new(x: u32) -> Option<Self> {
            if x != 0 {
                Some(NonZeroU32(x))
            } else {
                None
            }
        }

        #[inline]
        pub unsafe fn new_unchecked(x: u32) -> Self {
            NonZeroU32(x)
        }

        #[inline]
        pub fn get(self) -> u32 {
            self.0
        }
    }

    #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
    pub struct NonZeroUsize(usize);

    impl NonZeroUsize {
        #[inline]
        pub fn new(x: usize) -> Option<Self> {
            if x != 0 {
                Some(NonZeroUsize(x))
            } else {
                None
            }
        }

        #[inline]
        pub unsafe fn new_unchecked(x: usize) -> Self {
            NonZeroUsize(x)
        }

        #[inline]
        pub fn get(self) -> usize {
            self.0
        }
    }
}
<|endoftext|>


<commit_before>// This test case tests the incremental compilation hash (ICH) implementation
// for function interfaces.

// The general pattern followed here is: Change one thing between rev1 and rev2
// and make sure that the hash has changed, then change nothing between rev2 and
// rev3 and make sure that the hash has not changed.

// build-pass (FIXME(62277): could be check-pass?)
// revisions: cfail1 cfail2 cfail3
// compile-flags: -Z query-dep-graph -Zincremental-ignore-spans

#![allow(warnings)]
#![feature(linkage)]
#![feature(rustc_attrs)]
#![crate_type = "rlib"]

// Add Parameter ---------------------------------------------------------------

#[cfg(cfail1)]
pub fn add_parameter() {}

#[cfg(not(cfail1))]
#[rustc_clean(cfg = "cfail2",
              except = "hir_owner, hir_owner_items, mir_built, optimized_mir, typeck_tables_of, fn_sig")]
#[rustc_clean(cfg = "cfail3")]
pub fn add_parameter(p: i32) {}

// Add Return Type -------------------------------------------------------------

#[cfg(cfail1)]
pub fn add_return_type() {}

#[cfg(not(cfail1))]
#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_items")]
#[rustc_clean(cfg = "cfail3")]
pub fn add_return_type() -> () {}

// Change Parameter Type -------------------------------------------------------

#[cfg(cfail1)]
pub fn type_of_parameter(p: i32) {}

#[cfg(not(cfail1))]
#[rustc_clean(cfg = "cfail2",
              except = "hir_owner, hir_owner_items, mir_built, optimized_mir, typeck_tables_of, fn_sig")]
#[rustc_clean(cfg = "cfail3")]
pub fn type_of_parameter(p: i64) {}

// Change Parameter Type Reference ---------------------------------------------

#[cfg(cfail1)]
pub fn type_of_parameter_ref(p: &i32) {}

#[cfg(not(cfail1))]
#[rustc_clean(cfg = "cfail2",
              except = "hir_owner, hir_owner_items, mir_built, optimized_mir, typeck_tables_of, fn_sig")]
#[rustc_clean(cfg = "cfail3")]
pub fn type_of_parameter_ref(p: &mut i32) {}

// Change Parameter Order ------------------------------------------------------

#[cfg(cfail1)]
pub fn order_of_parameters(p1: i32, p2: i64) {}

#[cfg(not(cfail1))]
#[rustc_clean(cfg = "cfail2",
              except = "hir_owner, hir_owner_items, mir_built, optimized_mir, typeck_tables_of, fn_sig")]
#[rustc_clean(cfg = "cfail3")]
pub fn order_of_parameters(p2: i64, p1: i32) {}

// Unsafe ----------------------------------------------------------------------

#[cfg(cfail1)]
pub fn make_unsafe() {}

#[cfg(not(cfail1))]
#[rustc_clean(cfg = "cfail2",
              except = "hir_owner, hir_owner_items, mir_built, optimized_mir, typeck_tables_of, fn_sig")]
#[rustc_clean(cfg = "cfail3")]
pub unsafe fn make_unsafe() {}

// Extern ----------------------------------------------------------------------

#[cfg(cfail1)]
pub fn make_extern() {}

#[cfg(not(cfail1))]
#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_items, typeck_tables_of, fn_sig")]
#[rustc_clean(cfg = "cfail3")]
pub extern "C" fn make_extern() {}

// Type Parameter --------------------------------------------------------------

#[cfg(cfail1)]
pub fn type_parameter() {}

#[cfg(not(cfail1))]
#[rustc_clean(cfg = "cfail2",
              except = "hir_owner, hir_owner_items, generics_of, type_of, predicates_of")]
#[rustc_clean(cfg = "cfail3")]
pub fn type_parameter<T>() {}

// Lifetime Parameter ----------------------------------------------------------

#[cfg(cfail1)]
pub fn lifetime_parameter() {}

#[cfg(not(cfail1))]
#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_items, generics_of")]
#[rustc_clean(cfg = "cfail3")]
pub fn lifetime_parameter<'a>() {}

// Trait Bound -----------------------------------------------------------------

#[cfg(cfail1)]
pub fn trait_bound<T>() {}

#[cfg(not(cfail1))]
#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_items, predicates_of")]
#[rustc_clean(cfg = "cfail3")]
pub fn trait_bound<T: Eq>() {}

// Builtin Bound ---------------------------------------------------------------

#[cfg(cfail1)]
pub fn builtin_bound<T>() {}

#[cfg(not(cfail1))]
#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_items, predicates_of")]
#[rustc_clean(cfg = "cfail3")]
pub fn builtin_bound<T: Send>() {}

// Lifetime Bound --------------------------------------------------------------

#[cfg(cfail1)]
pub fn lifetime_bound<'a, T>() {}

#[cfg(not(cfail1))]
#[rustc_clean(cfg = "cfail2",
              except = "hir_owner, hir_owner_items, generics_of, type_of, predicates_of")]
#[rustc_clean(cfg = "cfail3")]
pub fn lifetime_bound<'a, T: 'a>() {}

// Second Trait Bound ----------------------------------------------------------

#[cfg(cfail1)]
pub fn second_trait_bound<T: Eq>() {}

#[cfg(not(cfail1))]
#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_items, predicates_of")]
#[rustc_clean(cfg = "cfail3")]
pub fn second_trait_bound<T: Eq + Clone>() {}

// Second Builtin Bound --------------------------------------------------------

#[cfg(cfail1)]
pub fn second_builtin_bound<T: Send>() {}

#[cfg(not(cfail1))]
#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_items, predicates_of")]
#[rustc_clean(cfg = "cfail3")]
pub fn second_builtin_bound<T: Send + Sized>() {}

// Second Lifetime Bound -------------------------------------------------------

#[cfg(cfail1)]
pub fn second_lifetime_bound<'a, 'b, T: 'a>() {}

#[cfg(not(cfail1))]
#[rustc_clean(cfg = "cfail2",
              except = "hir_owner, hir_owner_items, generics_of, type_of, predicates_of")]
#[rustc_clean(cfg = "cfail3")]
pub fn second_lifetime_bound<'a, 'b, T: 'a + 'b>() {}

// Inline ----------------------------------------------------------------------

#[cfg(cfail1)]
pub fn inline() {}

#[cfg(not(cfail1))]
#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_items")]
#[rustc_clean(cfg = "cfail3")]
#[inline]
pub fn inline() {}

// Inline Never ----------------------------------------------------------------

#[cfg(cfail1)]
#[inline(always)]
pub fn inline_never() {}

#[cfg(not(cfail1))]
#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_items")]
#[rustc_clean(cfg = "cfail3")]
#[inline(never)]
pub fn inline_never() {}

// No Mangle -------------------------------------------------------------------

#[cfg(cfail1)]
pub fn no_mangle() {}

#[cfg(not(cfail1))]
#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_items")]
#[rustc_clean(cfg = "cfail3")]
#[no_mangle]
pub fn no_mangle() {}

// Linkage ---------------------------------------------------------------------

#[cfg(cfail1)]
pub fn linkage() {}

#[cfg(not(cfail1))]
#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_items")]
#[rustc_clean(cfg = "cfail3")]
#[linkage = "weak_odr"]
pub fn linkage() {}

// Return Impl Trait -----------------------------------------------------------

#[cfg(cfail1)]
pub fn return_impl_trait() -> i32 {
    0
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_items, typeck_tables_of, fn_sig")]
#[rustc_clean(cfg = "cfail3")]
pub fn return_impl_trait() -> impl Clone {
    0
}

// Change Return Impl Trait ----------------------------------------------------

#[cfg(cfail1)]
pub fn change_return_impl_trait() -> impl Clone {
    0u32
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg = "cfail2")]
#[rustc_clean(cfg = "cfail3")]
pub fn change_return_impl_trait() -> impl Copy {
    0u32
}

// Change Return Type Indirectly -----------------------------------------------

pub struct ReferencedType1;
pub struct ReferencedType2;

pub mod change_return_type_indirectly {
    #[cfg(cfail1)]
    use super::ReferencedType1 as ReturnType;
    #[cfg(not(cfail1))]
    use super::ReferencedType2 as ReturnType;

    #[rustc_clean(cfg = "cfail2",
                  except = "hir_owner, hir_owner_items, mir_built, optimized_mir, typeck_tables_of, fn_sig")]
    #[rustc_clean(cfg = "cfail3")]
    pub fn indirect_return_type() -> ReturnType {
        ReturnType {}
    }
}

// Change Parameter Type Indirectly --------------------------------------------

pub mod change_parameter_type_indirectly {
    #[cfg(cfail1)]
    use super::ReferencedType1 as ParameterType;
    #[cfg(not(cfail1))]
    use super::ReferencedType2 as ParameterType;

    #[rustc_clean(cfg = "cfail2",
                  except = "hir_owner, hir_owner_items, mir_built, optimized_mir, typeck_tables_of, fn_sig")]
    #[rustc_clean(cfg = "cfail3")]
    pub fn indirect_parameter_type(p: ParameterType) {}
}

// Change Trait Bound Indirectly -----------------------------------------------

pub trait ReferencedTrait1 {}
pub trait ReferencedTrait2 {}

pub mod change_trait_bound_indirectly {
    #[cfg(cfail1)]
    use super::ReferencedTrait1 as Trait;
    #[cfg(not(cfail1))]
    use super::ReferencedTrait2 as Trait;

    #[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_items, predicates_of")]
    #[rustc_clean(cfg = "cfail3")]
    pub fn indirect_trait_bound<T: Trait>(p: T) {}
}

// Change Trait Bound Indirectly In Where Clause -------------------------------

pub mod change_trait_bound_indirectly_in_where_clause {
    #[cfg(cfail1)]
    use super::ReferencedTrait1 as Trait;
    #[cfg(not(cfail1))]
    use super::ReferencedTrait2 as Trait;

    #[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_items, predicates_of")]
    #[rustc_clean(cfg = "cfail3")]
    pub fn indirect_trait_bound_where<T>(p: T)
    where
        T: Trait,
    {
    }
}
<commit_msg>Format function_interfaces.rs<commit_after>// This test case tests the incremental compilation hash (ICH) implementation
// for function interfaces.

// The general pattern followed here is: Change one thing between rev1 and rev2
// and make sure that the hash has changed, then change nothing between rev2 and
// rev3 and make sure that the hash has not changed.

// build-pass (FIXME(62277): could be check-pass?)
// revisions: cfail1 cfail2 cfail3
// compile-flags: -Z query-dep-graph -Zincremental-ignore-spans

#![allow(warnings)]
#![feature(linkage)]
#![feature(rustc_attrs)]
#![crate_type = "rlib"]

// Add Parameter ---------------------------------------------------------------

#[cfg(cfail1)]
pub fn add_parameter() {}

#[cfg(not(cfail1))]
#[rustc_clean(
    cfg = "cfail2",
    except = "hir_owner, hir_owner_items, mir_built, optimized_mir, typeck_tables_of, fn_sig"
)]
#[rustc_clean(cfg = "cfail3")]
pub fn add_parameter(p: i32) {}

// Add Return Type -------------------------------------------------------------

#[cfg(cfail1)]
pub fn add_return_type() {}

#[cfg(not(cfail1))]
#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_items")]
#[rustc_clean(cfg = "cfail3")]
pub fn add_return_type() -> () {}

// Change Parameter Type -------------------------------------------------------

#[cfg(cfail1)]
pub fn type_of_parameter(p: i32) {}

#[cfg(not(cfail1))]
#[rustc_clean(
    cfg = "cfail2",
    except = "hir_owner, hir_owner_items, mir_built, optimized_mir, typeck_tables_of, fn_sig"
)]
#[rustc_clean(cfg = "cfail3")]
pub fn type_of_parameter(p: i64) {}

// Change Parameter Type Reference ---------------------------------------------

#[cfg(cfail1)]
pub fn type_of_parameter_ref(p: &i32) {}

#[cfg(not(cfail1))]
#[rustc_clean(
    cfg = "cfail2",
    except = "hir_owner, hir_owner_items, mir_built, optimized_mir, typeck_tables_of, fn_sig"
)]
#[rustc_clean(cfg = "cfail3")]
pub fn type_of_parameter_ref(p: &mut i32) {}

// Change Parameter Order ------------------------------------------------------

#[cfg(cfail1)]
pub fn order_of_parameters(p1: i32, p2: i64) {}

#[cfg(not(cfail1))]
#[rustc_clean(
    cfg = "cfail2",
    except = "hir_owner, hir_owner_items, mir_built, optimized_mir, typeck_tables_of, fn_sig"
)]
#[rustc_clean(cfg = "cfail3")]
pub fn order_of_parameters(p2: i64, p1: i32) {}

// Unsafe ----------------------------------------------------------------------

#[cfg(cfail1)]
pub fn make_unsafe() {}

#[cfg(not(cfail1))]
#[rustc_clean(
    cfg = "cfail2",
    except = "hir_owner, hir_owner_items, mir_built, optimized_mir, typeck_tables_of, fn_sig"
)]
#[rustc_clean(cfg = "cfail3")]
pub unsafe fn make_unsafe() {}

// Extern ----------------------------------------------------------------------

#[cfg(cfail1)]
pub fn make_extern() {}

#[cfg(not(cfail1))]
#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_items, typeck_tables_of, fn_sig")]
#[rustc_clean(cfg = "cfail3")]
pub extern "C" fn make_extern() {}

// Type Parameter --------------------------------------------------------------

#[cfg(cfail1)]
pub fn type_parameter() {}

#[cfg(not(cfail1))]
#[rustc_clean(
    cfg = "cfail2",
    except = "hir_owner, hir_owner_items, generics_of, type_of, predicates_of"
)]
#[rustc_clean(cfg = "cfail3")]
pub fn type_parameter<T>() {}

// Lifetime Parameter ----------------------------------------------------------

#[cfg(cfail1)]
pub fn lifetime_parameter() {}

#[cfg(not(cfail1))]
#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_items, generics_of")]
#[rustc_clean(cfg = "cfail3")]
pub fn lifetime_parameter<'a>() {}

// Trait Bound -----------------------------------------------------------------

#[cfg(cfail1)]
pub fn trait_bound<T>() {}

#[cfg(not(cfail1))]
#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_items, predicates_of")]
#[rustc_clean(cfg = "cfail3")]
pub fn trait_bound<T: Eq>() {}

// Builtin Bound ---------------------------------------------------------------

#[cfg(cfail1)]
pub fn builtin_bound<T>() {}

#[cfg(not(cfail1))]
#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_items, predicates_of")]
#[rustc_clean(cfg = "cfail3")]
pub fn builtin_bound<T: Send>() {}

// Lifetime Bound --------------------------------------------------------------

#[cfg(cfail1)]
pub fn lifetime_bound<'a, T>() {}

#[cfg(not(cfail1))]
#[rustc_clean(
    cfg = "cfail2",
    except = "hir_owner, hir_owner_items, generics_of, type_of, predicates_of"
)]
#[rustc_clean(cfg = "cfail3")]
pub fn lifetime_bound<'a, T: 'a>() {}

// Second Trait Bound ----------------------------------------------------------

#[cfg(cfail1)]
pub fn second_trait_bound<T: Eq>() {}

#[cfg(not(cfail1))]
#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_items, predicates_of")]
#[rustc_clean(cfg = "cfail3")]
pub fn second_trait_bound<T: Eq + Clone>() {}

// Second Builtin Bound --------------------------------------------------------

#[cfg(cfail1)]
pub fn second_builtin_bound<T: Send>() {}

#[cfg(not(cfail1))]
#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_items, predicates_of")]
#[rustc_clean(cfg = "cfail3")]
pub fn second_builtin_bound<T: Send + Sized>() {}

// Second Lifetime Bound -------------------------------------------------------

#[cfg(cfail1)]
pub fn second_lifetime_bound<'a, 'b, T: 'a>() {}

#[cfg(not(cfail1))]
#[rustc_clean(
    cfg = "cfail2",
    except = "hir_owner, hir_owner_items, generics_of, type_of, predicates_of"
)]
#[rustc_clean(cfg = "cfail3")]
pub fn second_lifetime_bound<'a, 'b, T: 'a + 'b>() {}

// Inline ----------------------------------------------------------------------

#[cfg(cfail1)]
pub fn inline() {}

#[cfg(not(cfail1))]
#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_items")]
#[rustc_clean(cfg = "cfail3")]
#[inline]
pub fn inline() {}

// Inline Never ----------------------------------------------------------------

#[cfg(cfail1)]
#[inline(always)]
pub fn inline_never() {}

#[cfg(not(cfail1))]
#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_items")]
#[rustc_clean(cfg = "cfail3")]
#[inline(never)]
pub fn inline_never() {}

// No Mangle -------------------------------------------------------------------

#[cfg(cfail1)]
pub fn no_mangle() {}

#[cfg(not(cfail1))]
#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_items")]
#[rustc_clean(cfg = "cfail3")]
#[no_mangle]
pub fn no_mangle() {}

// Linkage ---------------------------------------------------------------------

#[cfg(cfail1)]
pub fn linkage() {}

#[cfg(not(cfail1))]
#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_items")]
#[rustc_clean(cfg = "cfail3")]
#[linkage = "weak_odr"]
pub fn linkage() {}

// Return Impl Trait -----------------------------------------------------------

#[cfg(cfail1)]
pub fn return_impl_trait() -> i32 {
    0
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_items, typeck_tables_of, fn_sig")]
#[rustc_clean(cfg = "cfail3")]
pub fn return_impl_trait() -> impl Clone {
    0
}

// Change Return Impl Trait ----------------------------------------------------

#[cfg(cfail1)]
pub fn change_return_impl_trait() -> impl Clone {
    0u32
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg = "cfail2")]
#[rustc_clean(cfg = "cfail3")]
pub fn change_return_impl_trait() -> impl Copy {
    0u32
}

// Change Return Type Indirectly -----------------------------------------------

pub struct ReferencedType1;
pub struct ReferencedType2;

pub mod change_return_type_indirectly {
    #[cfg(cfail1)]
    use super::ReferencedType1 as ReturnType;
    #[cfg(not(cfail1))]
    use super::ReferencedType2 as ReturnType;

    #[rustc_clean(
        cfg = "cfail2",
        except = "hir_owner, hir_owner_items, mir_built, optimized_mir, typeck_tables_of, fn_sig"
    )]
    #[rustc_clean(cfg = "cfail3")]
    pub fn indirect_return_type() -> ReturnType {
        ReturnType {}
    }
}

// Change Parameter Type Indirectly --------------------------------------------

pub mod change_parameter_type_indirectly {
    #[cfg(cfail1)]
    use super::ReferencedType1 as ParameterType;
    #[cfg(not(cfail1))]
    use super::ReferencedType2 as ParameterType;

    #[rustc_clean(
        cfg = "cfail2",
        except = "hir_owner, hir_owner_items, mir_built, optimized_mir, typeck_tables_of, fn_sig"
    )]
    #[rustc_clean(cfg = "cfail3")]
    pub fn indirect_parameter_type(p: ParameterType) {}
}

// Change Trait Bound Indirectly -----------------------------------------------

pub trait ReferencedTrait1 {}
pub trait ReferencedTrait2 {}

pub mod change_trait_bound_indirectly {
    #[cfg(cfail1)]
    use super::ReferencedTrait1 as Trait;
    #[cfg(not(cfail1))]
    use super::ReferencedTrait2 as Trait;

    #[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_items, predicates_of")]
    #[rustc_clean(cfg = "cfail3")]
    pub fn indirect_trait_bound<T: Trait>(p: T) {}
}

// Change Trait Bound Indirectly In Where Clause -------------------------------

pub mod change_trait_bound_indirectly_in_where_clause {
    #[cfg(cfail1)]
    use super::ReferencedTrait1 as Trait;
    #[cfg(not(cfail1))]
    use super::ReferencedTrait2 as Trait;

    #[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_items, predicates_of")]
    #[rustc_clean(cfg = "cfail3")]
    pub fn indirect_trait_bound_where<T>(p: T)
    where
        T: Trait,
    {
    }
}
<|endoftext|>


<commit_before>// This stub file contains items which aren't used yet; feel free to remove this module attribute
// to enable stricter warnings.
#![allow(unused)]

#[derive(Debug)]
pub enum CalculatorInput {
    Add,
    Subtract,
    Multiply,
    Divide,
    Value(i32),
}

pub fn evaluate(inputs: &[CalculatorInput]) -> Option<i32> {
    unimplemented!(
		"Given the inputs: {:?}, evaluate them as though they were a Reverse Polish notation expression",
		inputs,
	);
}
<commit_msg>Reenable warning for unused code<commit_after>#[derive(Debug)]
pub enum CalculatorInput {
    Add,
    Subtract,
    Multiply,
    Divide,
    Value(i32),
}

pub fn evaluate(inputs: &[CalculatorInput]) -> Option<i32> {
    unimplemented!(
		"Given the inputs: {:?}, evaluate them as though they were a Reverse Polish notation expression",
		inputs,
	);
}
<|endoftext|>