<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/. */

<%namespace name="helpers" file="/helpers.mako.rs" />
<% from data import Keyword %>
<% data.new_style_struct("InheritedText", inherited=True, gecko_name="Text") %>

${helpers.predefined_type(
    "line-height",
    "LineHeight",
    "computed::LineHeight::normal()",
    animation_value_type="LineHeight",
    flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE \
           APPLIES_TO_PLACEHOLDER GETCS_NEEDS_LAYOUT_FLUSH",
    spec="https://drafts.csswg.org/css2/visudet.html#propdef-line-height",
    servo_restyle_damage="reflow"
)}

// CSS Text Module Level 3

// TODO(pcwalton): `full-width`
${helpers.single_keyword("text-transform",
                         "none capitalize uppercase lowercase",
                         extra_gecko_values="full-width",
                         animation_value_type="discrete",
                         flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
                         spec="https://drafts.csswg.org/css-text/#propdef-text-transform",
                         servo_restyle_damage="rebuild_and_reflow")}

${helpers.single_keyword("hyphens", "manual none auto",
                         gecko_enum_prefix="StyleHyphens",
                         products="gecko", animation_value_type="discrete", extra_prefixes="moz",
                         spec="https://drafts.csswg.org/css-text/#propdef-hyphens")}

// TODO: Support <percentage>
${helpers.single_keyword("-moz-text-size-adjust", "auto none",
                         gecko_constant_prefix="NS_STYLE_TEXT_SIZE_ADJUST",
                         gecko_ffi_name="mTextSizeAdjust",
                         products="gecko", animation_value_type="discrete",
                         spec="https://drafts.csswg.org/css-size-adjust/#adjustment-control",
                         alias="-webkit-text-size-adjust")}

${helpers.predefined_type("text-indent",
                          "LengthOrPercentage",
                          "computed::LengthOrPercentage::Length(computed::Length::new(0.))",
                          animation_value_type="ComputedValue",
                          spec="https://drafts.csswg.org/css-text/#propdef-text-indent",
                          allow_quirks=True, servo_restyle_damage = "reflow")}

// Also known as "word-wrap" (which is more popular because of IE), but this is the preferred
// name per CSS-TEXT 6.2.
${helpers.single_keyword("overflow-wrap",
                         "normal break-word",
                         gecko_constant_prefix="NS_STYLE_OVERFLOWWRAP",
                         animation_value_type="discrete",
                         spec="https://drafts.csswg.org/css-text/#propdef-overflow-wrap",
                         alias="word-wrap",
                         servo_restyle_damage="rebuild_and_reflow")}

// TODO(pcwalton): Support `word-break: keep-all` once we have better CJK support.
${helpers.single_keyword("word-break",
                         "normal break-all keep-all",
                         gecko_constant_prefix="NS_STYLE_WORDBREAK",
                         animation_value_type="discrete",
                         spec="https://drafts.csswg.org/css-text/#propdef-word-break",
                         servo_restyle_damage="rebuild_and_reflow")}

// TODO(pcwalton): Support `text-justify: distribute`.
<%helpers:single_keyword
    name="text-justify"
    values="auto none inter-word"
    extra_gecko_values="inter-character"
    extra_specified="${'distribute' if product == 'gecko' else ''}"
    gecko_enum_prefix="StyleTextJustify"
    animation_value_type="discrete"
    gecko_pref="layout.css.text-justify.enabled"
    flags="APPLIES_TO_PLACEHOLDER",
    spec="https://drafts.csswg.org/css-text/#propdef-text-justify"
    servo_restyle_damage="rebuild_and_reflow"
>
    % if product == 'gecko':
    impl ToComputedValue for SpecifiedValue {
        type ComputedValue = computed_value::T;

        #[inline]
        fn to_computed_value(&self, _: &Context) -> computed_value::T {
            match *self {
                % for value in "Auto None InterCharacter InterWord".split():
                SpecifiedValue::${value} => computed_value::T::${value},
                % endfor
                // https://drafts.csswg.org/css-text-3/#valdef-text-justify-distribute
                SpecifiedValue::Distribute => computed_value::T::InterCharacter,
            }
        }

        #[inline]
        fn from_computed_value(computed: &computed_value::T) -> SpecifiedValue {
            match *computed {
                % for value in "Auto None InterCharacter InterWord".split():
                computed_value::T::${value} => SpecifiedValue::${value},
                % endfor
            }
        }
    }
    % endif
</%helpers:single_keyword>

${helpers.single_keyword("text-align-last",
                         "auto start end left right center justify",
                         products="gecko",
                         gecko_constant_prefix="NS_STYLE_TEXT_ALIGN",
                         animation_value_type="discrete",
                         spec="https://drafts.csswg.org/css-text/#propdef-text-align-last")}

// TODO make this a shorthand and implement text-align-last/text-align-all
//
// FIXME(emilio): This can't really be that complicated.
${helpers.predefined_type("text-align",
                          "TextAlign",
                          "computed::TextAlign::start()",
                          animation_value_type="discrete",
                          flags="APPLIES_TO_PLACEHOLDER",
                          spec="https://drafts.csswg.org/css-text/#propdef-text-align",
                          servo_restyle_damage = "reflow")}

${helpers.predefined_type("letter-spacing",
                          "LetterSpacing",
                          "computed::LetterSpacing::normal()",
                          animation_value_type="ComputedValue",
                          flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
                          spec="https://drafts.csswg.org/css-text/#propdef-letter-spacing",
                          servo_restyle_damage="rebuild_and_reflow")}

${helpers.predefined_type("word-spacing",
                          "WordSpacing",
                          "computed::WordSpacing::normal()",
                          animation_value_type="ComputedValue",
                          flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
                          spec="https://drafts.csswg.org/css-text/#propdef-word-spacing",
                          servo_restyle_damage="rebuild_and_reflow")}

<%helpers:single_keyword
    name="white-space"
    values="normal pre nowrap pre-wrap pre-line"
    extra_gecko_values="-moz-pre-space"
    gecko_enum_prefix="StyleWhiteSpace"
    needs_conversion="True"
    animation_value_type="discrete"
    // Only allowed for UA sheets, which set it !important.
    flags="APPLIES_TO_PLACEHOLDER"
    spec="https://drafts.csswg.org/css-text/#propdef-white-space"
    servo_restyle_damage="rebuild_and_reflow"
>
    % if product != "gecko":
    impl SpecifiedValue {
        pub fn allow_wrap(&self) -> bool {
            match *self {
                SpecifiedValue::Nowrap |
                SpecifiedValue::Pre => false,
                SpecifiedValue::Normal |
                SpecifiedValue::PreWrap |
                SpecifiedValue::PreLine => true,
            }
        }

        pub fn preserve_newlines(&self) -> bool {
            match *self {
                SpecifiedValue::Normal |
                SpecifiedValue::Nowrap => false,
                SpecifiedValue::Pre |
                SpecifiedValue::PreWrap |
                SpecifiedValue::PreLine => true,
            }
        }

        pub fn preserve_spaces(&self) -> bool {
            match *self {
                SpecifiedValue::Normal |
                SpecifiedValue::Nowrap |
                SpecifiedValue::PreLine => false,
                SpecifiedValue::Pre |
                SpecifiedValue::PreWrap => true,
            }
        }
    }
    % endif
</%helpers:single_keyword>

${helpers.predefined_type(
    "text-shadow",
    "SimpleShadow",
    None,
    vector=True,
    animation_value_type="AnimatedTextShadowList",
    ignored_when_colors_disabled=True,
    flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
    spec="https://drafts.csswg.org/css-text-decor-3/#text-shadow-property",
)}

${helpers.predefined_type(
    "text-emphasis-style",
    "TextEmphasisStyle",
    None,
    initial_specified_value="SpecifiedValue::None",
    products="gecko",
    boxed=True,
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-text-decor/#propdef-text-emphasis-style",
)}

${helpers.predefined_type(
    "text-emphasis-position",
    "TextEmphasisPosition",
    "computed::TextEmphasisPosition::over_right()",
    initial_specified_value="specified::TextEmphasisPosition::over_right()",
    products="gecko",
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-text-decor/#propdef-text-emphasis-position",
)}

${helpers.predefined_type(
    "text-emphasis-color",
    "Color",
    "computed_value::T::currentcolor()",
    initial_specified_value="specified::Color::currentcolor()",
    products="gecko",
    animation_value_type="AnimatedColor",
    ignored_when_colors_disabled=True,
    spec="https://drafts.csswg.org/css-text-decor/#propdef-text-emphasis-color",
)}

${helpers.predefined_type(
    "-moz-tab-size",
    "MozTabSize",
    "generics::text::MozTabSize::Number(From::from(8.0))",
    products="gecko",
    animation_value_type="AnimatedMozTabSize",
    spec="https://drafts.csswg.org/css-text-3/#tab-size-property",
)}

// CSS Compatibility
// https://compat.spec.whatwg.org
${helpers.predefined_type(
    "-webkit-text-fill-color",
    "Color",
    "computed_value::T::currentcolor()",
    products="gecko",
    gecko_pref="layout.css.prefixes.webkit",
    animation_value_type="AnimatedColor",
    ignored_when_colors_disabled=True,
    flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
    spec="https://compat.spec.whatwg.org/#the-webkit-text-fill-color",
)}

${helpers.predefined_type(
    "-webkit-text-stroke-color",
    "Color",
    "computed_value::T::currentcolor()",
    initial_specified_value="specified::Color::currentcolor()",
    products="gecko",
    animation_value_type="AnimatedColor",
    ignored_when_colors_disabled=True,
    gecko_pref="layout.css.prefixes.webkit",
    flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
    spec="https://compat.spec.whatwg.org/#the-webkit-text-stroke-color",
)}

${helpers.predefined_type("-webkit-text-stroke-width",
                          "BorderSideWidth",
                          "::values::computed::NonNegativeLength::new(0.)",
                          initial_specified_value="specified::BorderSideWidth::Length(specified::Length::zero())",
                          computed_type="::values::computed::NonNegativeLength",
                          products="gecko",
                          gecko_pref="layout.css.prefixes.webkit",
                          flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
                          spec="https://compat.spec.whatwg.org/#the-webkit-text-stroke-width",
                          animation_value_type="discrete")}

// CSS Ruby Layout Module Level 1
// https://drafts.csswg.org/css-ruby/
${helpers.single_keyword("ruby-align", "space-around start center space-between",
                         products="gecko", animation_value_type="discrete",
                         spec="https://drafts.csswg.org/css-ruby/#ruby-align-property")}

${helpers.single_keyword("ruby-position", "over under",
                         products="gecko", animation_value_type="discrete",
                         spec="https://drafts.csswg.org/css-ruby/#ruby-position-property")}

// CSS Writing Modes Module Level 3
// https://drafts.csswg.org/css-writing-modes-3/

${helpers.single_keyword("text-combine-upright", "none all",
                         products="gecko", animation_value_type="discrete",
                         gecko_pref="layout.css.text-combine-upright.enabled",
                         spec="https://drafts.csswg.org/css-writing-modes-3/#text-combine-upright")}

// SVG 1.1: Section 11 - Painting: Filling, Stroking and Marker Symbols
${helpers.single_keyword("text-rendering",
                         "auto optimizespeed optimizelegibility geometricprecision",
                         animation_value_type="discrete",
                         spec="https://www.w3.org/TR/SVG11/painting.html#TextRenderingProperty",
                         servo_restyle_damage="rebuild_and_reflow")}

// FIXME Firefox expects the initial value of this property to change depending
// on the value of the layout.css.control-characters.visible pref.
${helpers.single_keyword("-moz-control-character-visibility",
                         "hidden visible",
                         gecko_constant_prefix="NS_STYLE_CONTROL_CHARACTER_VISIBILITY",
                         gecko_ffi_name="mControlCharacterVisibility",
                         animation_value_type="none",
                         products="gecko",
                         spec="Nonstandard")}
<commit_msg>style: Remove "layout.css.text-combine-upright.enabled" pref.<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/. */

<%namespace name="helpers" file="/helpers.mako.rs" />
<% from data import Keyword %>
<% data.new_style_struct("InheritedText", inherited=True, gecko_name="Text") %>

${helpers.predefined_type(
    "line-height",
    "LineHeight",
    "computed::LineHeight::normal()",
    animation_value_type="LineHeight",
    flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE \
           APPLIES_TO_PLACEHOLDER GETCS_NEEDS_LAYOUT_FLUSH",
    spec="https://drafts.csswg.org/css2/visudet.html#propdef-line-height",
    servo_restyle_damage="reflow"
)}

// CSS Text Module Level 3

// TODO(pcwalton): `full-width`
${helpers.single_keyword("text-transform",
                         "none capitalize uppercase lowercase",
                         extra_gecko_values="full-width",
                         animation_value_type="discrete",
                         flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
                         spec="https://drafts.csswg.org/css-text/#propdef-text-transform",
                         servo_restyle_damage="rebuild_and_reflow")}

${helpers.single_keyword("hyphens", "manual none auto",
                         gecko_enum_prefix="StyleHyphens",
                         products="gecko", animation_value_type="discrete", extra_prefixes="moz",
                         spec="https://drafts.csswg.org/css-text/#propdef-hyphens")}

// TODO: Support <percentage>
${helpers.single_keyword("-moz-text-size-adjust", "auto none",
                         gecko_constant_prefix="NS_STYLE_TEXT_SIZE_ADJUST",
                         gecko_ffi_name="mTextSizeAdjust",
                         products="gecko", animation_value_type="discrete",
                         spec="https://drafts.csswg.org/css-size-adjust/#adjustment-control",
                         alias="-webkit-text-size-adjust")}

${helpers.predefined_type("text-indent",
                          "LengthOrPercentage",
                          "computed::LengthOrPercentage::Length(computed::Length::new(0.))",
                          animation_value_type="ComputedValue",
                          spec="https://drafts.csswg.org/css-text/#propdef-text-indent",
                          allow_quirks=True, servo_restyle_damage = "reflow")}

// Also known as "word-wrap" (which is more popular because of IE), but this is the preferred
// name per CSS-TEXT 6.2.
${helpers.single_keyword("overflow-wrap",
                         "normal break-word",
                         gecko_constant_prefix="NS_STYLE_OVERFLOWWRAP",
                         animation_value_type="discrete",
                         spec="https://drafts.csswg.org/css-text/#propdef-overflow-wrap",
                         alias="word-wrap",
                         servo_restyle_damage="rebuild_and_reflow")}

// TODO(pcwalton): Support `word-break: keep-all` once we have better CJK support.
${helpers.single_keyword("word-break",
                         "normal break-all keep-all",
                         gecko_constant_prefix="NS_STYLE_WORDBREAK",
                         animation_value_type="discrete",
                         spec="https://drafts.csswg.org/css-text/#propdef-word-break",
                         servo_restyle_damage="rebuild_and_reflow")}

// TODO(pcwalton): Support `text-justify: distribute`.
<%helpers:single_keyword
    name="text-justify"
    values="auto none inter-word"
    extra_gecko_values="inter-character"
    extra_specified="${'distribute' if product == 'gecko' else ''}"
    gecko_enum_prefix="StyleTextJustify"
    animation_value_type="discrete"
    gecko_pref="layout.css.text-justify.enabled"
    flags="APPLIES_TO_PLACEHOLDER",
    spec="https://drafts.csswg.org/css-text/#propdef-text-justify"
    servo_restyle_damage="rebuild_and_reflow"
>
    % if product == 'gecko':
    impl ToComputedValue for SpecifiedValue {
        type ComputedValue = computed_value::T;

        #[inline]
        fn to_computed_value(&self, _: &Context) -> computed_value::T {
            match *self {
                % for value in "Auto None InterCharacter InterWord".split():
                SpecifiedValue::${value} => computed_value::T::${value},
                % endfor
                // https://drafts.csswg.org/css-text-3/#valdef-text-justify-distribute
                SpecifiedValue::Distribute => computed_value::T::InterCharacter,
            }
        }

        #[inline]
        fn from_computed_value(computed: &computed_value::T) -> SpecifiedValue {
            match *computed {
                % for value in "Auto None InterCharacter InterWord".split():
                computed_value::T::${value} => SpecifiedValue::${value},
                % endfor
            }
        }
    }
    % endif
</%helpers:single_keyword>

${helpers.single_keyword("text-align-last",
                         "auto start end left right center justify",
                         products="gecko",
                         gecko_constant_prefix="NS_STYLE_TEXT_ALIGN",
                         animation_value_type="discrete",
                         spec="https://drafts.csswg.org/css-text/#propdef-text-align-last")}

// TODO make this a shorthand and implement text-align-last/text-align-all
//
// FIXME(emilio): This can't really be that complicated.
${helpers.predefined_type("text-align",
                          "TextAlign",
                          "computed::TextAlign::start()",
                          animation_value_type="discrete",
                          flags="APPLIES_TO_PLACEHOLDER",
                          spec="https://drafts.csswg.org/css-text/#propdef-text-align",
                          servo_restyle_damage = "reflow")}

${helpers.predefined_type("letter-spacing",
                          "LetterSpacing",
                          "computed::LetterSpacing::normal()",
                          animation_value_type="ComputedValue",
                          flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
                          spec="https://drafts.csswg.org/css-text/#propdef-letter-spacing",
                          servo_restyle_damage="rebuild_and_reflow")}

${helpers.predefined_type("word-spacing",
                          "WordSpacing",
                          "computed::WordSpacing::normal()",
                          animation_value_type="ComputedValue",
                          flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
                          spec="https://drafts.csswg.org/css-text/#propdef-word-spacing",
                          servo_restyle_damage="rebuild_and_reflow")}

<%helpers:single_keyword
    name="white-space"
    values="normal pre nowrap pre-wrap pre-line"
    extra_gecko_values="-moz-pre-space"
    gecko_enum_prefix="StyleWhiteSpace"
    needs_conversion="True"
    animation_value_type="discrete"
    // Only allowed for UA sheets, which set it !important.
    flags="APPLIES_TO_PLACEHOLDER"
    spec="https://drafts.csswg.org/css-text/#propdef-white-space"
    servo_restyle_damage="rebuild_and_reflow"
>
    % if product != "gecko":
    impl SpecifiedValue {
        pub fn allow_wrap(&self) -> bool {
            match *self {
                SpecifiedValue::Nowrap |
                SpecifiedValue::Pre => false,
                SpecifiedValue::Normal |
                SpecifiedValue::PreWrap |
                SpecifiedValue::PreLine => true,
            }
        }

        pub fn preserve_newlines(&self) -> bool {
            match *self {
                SpecifiedValue::Normal |
                SpecifiedValue::Nowrap => false,
                SpecifiedValue::Pre |
                SpecifiedValue::PreWrap |
                SpecifiedValue::PreLine => true,
            }
        }

        pub fn preserve_spaces(&self) -> bool {
            match *self {
                SpecifiedValue::Normal |
                SpecifiedValue::Nowrap |
                SpecifiedValue::PreLine => false,
                SpecifiedValue::Pre |
                SpecifiedValue::PreWrap => true,
            }
        }
    }
    % endif
</%helpers:single_keyword>

${helpers.predefined_type(
    "text-shadow",
    "SimpleShadow",
    None,
    vector=True,
    animation_value_type="AnimatedTextShadowList",
    ignored_when_colors_disabled=True,
    flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
    spec="https://drafts.csswg.org/css-text-decor-3/#text-shadow-property",
)}

${helpers.predefined_type(
    "text-emphasis-style",
    "TextEmphasisStyle",
    None,
    initial_specified_value="SpecifiedValue::None",
    products="gecko",
    boxed=True,
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-text-decor/#propdef-text-emphasis-style",
)}

${helpers.predefined_type(
    "text-emphasis-position",
    "TextEmphasisPosition",
    "computed::TextEmphasisPosition::over_right()",
    initial_specified_value="specified::TextEmphasisPosition::over_right()",
    products="gecko",
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-text-decor/#propdef-text-emphasis-position",
)}

${helpers.predefined_type(
    "text-emphasis-color",
    "Color",
    "computed_value::T::currentcolor()",
    initial_specified_value="specified::Color::currentcolor()",
    products="gecko",
    animation_value_type="AnimatedColor",
    ignored_when_colors_disabled=True,
    spec="https://drafts.csswg.org/css-text-decor/#propdef-text-emphasis-color",
)}

${helpers.predefined_type(
    "-moz-tab-size",
    "MozTabSize",
    "generics::text::MozTabSize::Number(From::from(8.0))",
    products="gecko",
    animation_value_type="AnimatedMozTabSize",
    spec="https://drafts.csswg.org/css-text-3/#tab-size-property",
)}

// CSS Compatibility
// https://compat.spec.whatwg.org
${helpers.predefined_type(
    "-webkit-text-fill-color",
    "Color",
    "computed_value::T::currentcolor()",
    products="gecko",
    gecko_pref="layout.css.prefixes.webkit",
    animation_value_type="AnimatedColor",
    ignored_when_colors_disabled=True,
    flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
    spec="https://compat.spec.whatwg.org/#the-webkit-text-fill-color",
)}

${helpers.predefined_type(
    "-webkit-text-stroke-color",
    "Color",
    "computed_value::T::currentcolor()",
    initial_specified_value="specified::Color::currentcolor()",
    products="gecko",
    animation_value_type="AnimatedColor",
    ignored_when_colors_disabled=True,
    gecko_pref="layout.css.prefixes.webkit",
    flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
    spec="https://compat.spec.whatwg.org/#the-webkit-text-stroke-color",
)}

${helpers.predefined_type("-webkit-text-stroke-width",
                          "BorderSideWidth",
                          "::values::computed::NonNegativeLength::new(0.)",
                          initial_specified_value="specified::BorderSideWidth::Length(specified::Length::zero())",
                          computed_type="::values::computed::NonNegativeLength",
                          products="gecko",
                          gecko_pref="layout.css.prefixes.webkit",
                          flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
                          spec="https://compat.spec.whatwg.org/#the-webkit-text-stroke-width",
                          animation_value_type="discrete")}

// CSS Ruby Layout Module Level 1
// https://drafts.csswg.org/css-ruby/
${helpers.single_keyword("ruby-align", "space-around start center space-between",
                         products="gecko", animation_value_type="discrete",
                         spec="https://drafts.csswg.org/css-ruby/#ruby-align-property")}

${helpers.single_keyword("ruby-position", "over under",
                         products="gecko", animation_value_type="discrete",
                         spec="https://drafts.csswg.org/css-ruby/#ruby-position-property")}

// CSS Writing Modes Module Level 3
// https://drafts.csswg.org/css-writing-modes-3/

${helpers.single_keyword("text-combine-upright", "none all",
                         products="gecko", animation_value_type="discrete",
                         spec="https://drafts.csswg.org/css-writing-modes-3/#text-combine-upright")}

// SVG 1.1: Section 11 - Painting: Filling, Stroking and Marker Symbols
${helpers.single_keyword("text-rendering",
                         "auto optimizespeed optimizelegibility geometricprecision",
                         animation_value_type="discrete",
                         spec="https://www.w3.org/TR/SVG11/painting.html#TextRenderingProperty",
                         servo_restyle_damage="rebuild_and_reflow")}

// FIXME Firefox expects the initial value of this property to change depending
// on the value of the layout.css.control-characters.visible pref.
${helpers.single_keyword("-moz-control-character-visibility",
                         "hidden visible",
                         gecko_constant_prefix="NS_STYLE_CONTROL_CHARACTER_VISIBILITY",
                         gecko_ffi_name="mControlCharacterVisibility",
                         animation_value_type="none",
                         products="gecko",
                         spec="Nonstandard")}
<|endoftext|>


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

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

declare_lint_pass!(UnnecessaryWrap => [UNNECESSARY_WRAP]);

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

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

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

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

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

declare_lint_pass!(UnnecessaryWrap => [UNNECESSARY_WRAP]);

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

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

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

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


<commit_before>use inkwell::context::Context;
use inkwell::debug_info::{
    AsDIScope, DIFlags, DIFlagsConstants, DISubprogram, DWARFEmissionKind, DWARFSourceLanguage,
};
use inkwell::module::FlagBehavior;

#[test]
fn test_smoke() {
    let context = Context::create();
    let module = context.create_module("bin");

    let debug_metadata_version = context.i32_type().const_int(3, false);
    module.add_basic_value_flag(
        "Debug Info Version",
        FlagBehavior::Warning,
        debug_metadata_version,
    );
    let builder = context.create_builder();
    let (dibuilder, compile_unit) = module.create_debug_info_builder(
        true,
        DWARFSourceLanguage::C,
        "source_file",
        ".",
        "my llvm compiler frontend",
        false,
        "",
        0,
        "",
        DWARFEmissionKind::Full,
        0,
        false,
        false,
        #[cfg(feature = "llvm11-0")]
        "",
        #[cfg(feature = "llvm11-0")]
        "",
    );

    let ditype = dibuilder
        .create_basic_type(
            "type_name",
            0_u64,
            0x00,
            #[cfg(not(feature = "llvm7-0"))]
            DIFlags::PUBLIC,
        )
        .unwrap();
    let subroutine_type = dibuilder.create_subroutine_type(
        compile_unit.get_file(),
        Some(ditype.as_type()),
        &[],
        DIFlags::PUBLIC,
    );
    let func_scope: DISubprogram<'_> = dibuilder.create_function(
        compile_unit.as_debug_info_scope(),
        "main",
        None,
        compile_unit.get_file(),
        0,
        subroutine_type,
        true,
        true,
        0,
        DIFlags::PUBLIC,
        false,
    );

    let fn_type = context.i64_type().fn_type(&[], false);
    let fn_val = module.add_function("fn_name_str", fn_type, None);
    fn_val.set_subprogram(func_scope);

    let basic_block = context.append_basic_block(fn_val, "entry");
    builder.position_at_end(basic_block);
    builder.build_return(Some(&context.i64_type().const_zero()));

    let lexical_block = dibuilder.create_lexical_block(
        func_scope.as_debug_info_scope(),
        compile_unit.get_file(),
        0,
        0,
    );

    let loc =
        dibuilder.create_debug_location(&context, 0, 0, lexical_block.as_debug_info_scope(), None);
    builder.set_current_debug_location(&context, loc);

    dibuilder.finalize();

    assert!(module.verify().is_ok());
}

#[test]
fn test_struct_with_placeholders() {
    let context = Context::create();
    let module = context.create_module("");

    let (dibuilder, compile_unit) = module.create_debug_info_builder(
        true,
        DWARFSourceLanguage::C,
        "source_file",
        ".",
        "my llvm compiler frontend",
        false,
        "",
        0,
        "",
        DWARFEmissionKind::Full,
        0,
        false,
        false,
        #[cfg(feature = "llvm11-0")]
        "",
        #[cfg(feature = "llvm11-0")]
        "",
    );

    // Some byte aligned integer types.
    let i32ty = dibuilder
        .create_basic_type(
            "i32",
            32,
            0x07,
            #[cfg(not(feature = "llvm7-0"))]
            DIFlags::PUBLIC,
        )
        .unwrap();
    let i64ty = dibuilder
        .create_basic_type(
            "i64",
            64,
            0x07,
            #[cfg(not(feature = "llvm7-0"))]
            DIFlags::PUBLIC,
        )
        .unwrap();
    let f32ty = dibuilder
        .create_basic_type(
            "f32",
            32,
            0x04,
            #[cfg(not(feature = "llvm7-0"))]
            DIFlags::PUBLIC,
        )
        .unwrap();
    let f64ty = dibuilder
        .create_basic_type(
            "f64",
            64,
            0x04,
            #[cfg(not(feature = "llvm7-0"))]
            DIFlags::PUBLIC,
        )
        .unwrap();

    let member_sizes = vec![32, 64, 32, 64];
    let member_types = vec![i32ty, i64ty, f32ty, f64ty];
    let member_placeholders = member_types
        .iter()
        .map(|_ty| unsafe { dibuilder.create_placeholder_derived_type(&context) })
        .collect::<Vec<_>>();
    let member_placeholders_as_ditype = member_types
        .iter()
        .map(|ty| ty.as_type())
        .collect::<Vec<_>>();

    let structty = dibuilder.create_struct_type(
        compile_unit.get_file().as_debug_info_scope(),
        "",
        compile_unit.get_file(),
        0,
        192,
        8,
        DIFlags::PUBLIC,
        None,
        member_placeholders_as_ditype.as_slice(),
        0,
        None,
        "",
    );

    let mut offset = 0;
    for ((placeholder, ty), size) in member_placeholders
        .iter()
        .zip(member_types.iter())
        .zip(member_sizes.iter())
    {
        let member = dibuilder.create_member_type(
            structty.as_debug_info_scope(),
            "",
            compile_unit.get_file(),
            0,
            *size,
            8,
            offset,
            DIFlags::PUBLIC,
            ty.as_type(),
        );
        unsafe {
            dibuilder.replace_placeholder_derived_type(*placeholder, member);
        }
        offset += size;
    }

    dibuilder.finalize();

    assert!(module.verify().is_ok());
}

#[test]
fn test_no_explicit_finalize() {
    let context = Context::create();
    let module = context.create_module("");

    let (dibuilder, _compile_unit) = module.create_debug_info_builder(
        true,
        DWARFSourceLanguage::C,
        "source_file",
        ".",
        "my llvm compiler frontend",
        false,
        "",
        0,
        "",
        DWARFEmissionKind::Full,
        0,
        false,
        false,
        #[cfg(feature = "llvm11-0")]
        "",
        #[cfg(feature = "llvm11-0")]
        "",
    );

    drop(dibuilder);

    assert!(module.verify().is_ok());
}

#[llvm_versions(8.0..=latest)]
#[test]
fn test_replacing_placeholder_with_placeholder() {
    let context = Context::create();
    let module = context.create_module("");

    let (dibuilder, compile_unit) = module.create_debug_info_builder(
        true,
        DWARFSourceLanguage::C,
        "source_file",
        ".",
        "my llvm compiler frontend",
        false,
        "",
        0,
        "",
        DWARFEmissionKind::Full,
        0,
        false,
        false,
        #[cfg(feature = "llvm11-0")]
        "",
        #[cfg(feature = "llvm11-0")]
        "",
    );

    let i32ty = dibuilder
        .create_basic_type("i32", 32, 0x07, DIFlags::PUBLIC)
        .unwrap();
    let typedefty = dibuilder.create_typedef(
        i32ty.as_type(),
        "",
        compile_unit.get_file(),
        0,
        compile_unit.get_file().as_debug_info_scope(),
        #[cfg(not(any(feature = "llvm8-0", feature = "llvm9-0")))]
        32,
    );

    unsafe {
        let ph1 = dibuilder.create_placeholder_derived_type(&context);
        let ph2 = dibuilder.create_placeholder_derived_type(&context);

        dibuilder.replace_placeholder_derived_type(ph2, ph1);
        dibuilder.replace_placeholder_derived_type(ph1, typedefty);
    }
}

#[test]
fn test_anonymous_basic_type() {
    let context = Context::create();
    let module = context.create_module("bin");

    let (dibuilder, _compile_unit) = module.create_debug_info_builder(
        true,
        DWARFSourceLanguage::C,
        "source_file",
        ".",
        "my llvm compiler frontend",
        false,
        "",
        0,
        "",
        DWARFEmissionKind::Full,
        0,
        false,
        false,
        #[cfg(feature = "llvm11-0")]
        "",
        #[cfg(feature = "llvm11-0")]
        "",
    );

    assert_eq!(
        dibuilder.create_basic_type(
            "",
            0_u64,
            0x00,
            #[cfg(not(feature = "llvm7-0"))]
            DIFlags::ZERO
        ),
        Err("basic types must have names")
    );
}

#[llvm_versions(8.0..=latest)]
#[test]
fn test_global_expressions() {
    let context = Context::create();
    let module = context.create_module("bin");

    let (dibuilder, compile_unit) = module.create_debug_info_builder(
        true,
        DWARFSourceLanguage::C,
        "source_file",
        ".",
        "my llvm compiler frontend",
        false,
        "",
        0,
        "",
        DWARFEmissionKind::Full,
        0,
        false,
        false,
        #[cfg(feature = "llvm11-0")]
        "",
        #[cfg(feature = "llvm11-0")]
        "",
    );

    let di_type = dibuilder.create_basic_type("type_name", 0_u64, 0x00, DIFlags::ZERO);
    let gv = module.add_global(context.i64_type(), Some(inkwell::AddressSpace::Global), "gv");

    let const_v = dibuilder.create_constant_expression(10);

    let gv_debug = dibuilder.create_global_variable_expression(
        compile_unit.as_debug_info_scope(),
        "gv",
        "",
        compile_unit.get_file(),
        1,
        di_type.unwrap().as_type(),
        true,
        Some(const_v),
        None,
        8,
    );

    let metadata = context.metadata_node(&[gv_debug.as_metadata_value(&context).into()]);

    gv.set_metadata(metadata, 0);

    // TODO: Metadata set on the global values cannot be retrieved using the C api,
    // therefore, it's currently not possible to test that the data was set without generating the IR
    assert!(gv.print_to_string().to_string().contains("!dbg"), format!("expected !dbg but generated gv was {}",gv.print_to_string()));
}
<commit_msg>llvm 12 compat in debug_info tests<commit_after>use inkwell::context::Context;
use inkwell::debug_info::{
    AsDIScope, DIFlags, DIFlagsConstants, DISubprogram, DWARFEmissionKind, DWARFSourceLanguage,
};
use inkwell::module::FlagBehavior;

#[test]
fn test_smoke() {
    let context = Context::create();
    let module = context.create_module("bin");

    let debug_metadata_version = context.i32_type().const_int(3, false);
    module.add_basic_value_flag(
        "Debug Info Version",
        FlagBehavior::Warning,
        debug_metadata_version,
    );
    let builder = context.create_builder();
    let (dibuilder, compile_unit) = module.create_debug_info_builder(
        true,
        DWARFSourceLanguage::C,
        "source_file",
        ".",
        "my llvm compiler frontend",
        false,
        "",
        0,
        "",
        DWARFEmissionKind::Full,
        0,
        false,
        false,
        #[cfg(any(feature = "llvm11-0", feature = "llvm12-0"))]
        "",
        #[cfg(any(feature = "llvm11-0", feature = "llvm12-0"))]
        "",
    );

    let ditype = dibuilder
        .create_basic_type(
            "type_name",
            0_u64,
            0x00,
            #[cfg(not(feature = "llvm7-0"))]
            DIFlags::PUBLIC,
        )
        .unwrap();
    let subroutine_type = dibuilder.create_subroutine_type(
        compile_unit.get_file(),
        Some(ditype.as_type()),
        &[],
        DIFlags::PUBLIC,
    );
    let func_scope: DISubprogram<'_> = dibuilder.create_function(
        compile_unit.as_debug_info_scope(),
        "main",
        None,
        compile_unit.get_file(),
        0,
        subroutine_type,
        true,
        true,
        0,
        DIFlags::PUBLIC,
        false,
    );

    let fn_type = context.i64_type().fn_type(&[], false);
    let fn_val = module.add_function("fn_name_str", fn_type, None);
    fn_val.set_subprogram(func_scope);

    let basic_block = context.append_basic_block(fn_val, "entry");
    builder.position_at_end(basic_block);
    builder.build_return(Some(&context.i64_type().const_zero()));

    let lexical_block = dibuilder.create_lexical_block(
        func_scope.as_debug_info_scope(),
        compile_unit.get_file(),
        0,
        0,
    );

    let loc =
        dibuilder.create_debug_location(&context, 0, 0, lexical_block.as_debug_info_scope(), None);
    builder.set_current_debug_location(&context, loc);

    dibuilder.finalize();

    assert!(module.verify().is_ok());
}

#[test]
fn test_struct_with_placeholders() {
    let context = Context::create();
    let module = context.create_module("");

    let (dibuilder, compile_unit) = module.create_debug_info_builder(
        true,
        DWARFSourceLanguage::C,
        "source_file",
        ".",
        "my llvm compiler frontend",
        false,
        "",
        0,
        "",
        DWARFEmissionKind::Full,
        0,
        false,
        false,
        #[cfg(any(feature = "llvm11-0", feature = "llvm12-0"))]
        "",
        #[cfg(any(feature = "llvm11-0", feature = "llvm12-0"))]
        "",
    );

    // Some byte aligned integer types.
    let i32ty = dibuilder
        .create_basic_type(
            "i32",
            32,
            0x07,
            #[cfg(not(feature = "llvm7-0"))]
            DIFlags::PUBLIC,
        )
        .unwrap();
    let i64ty = dibuilder
        .create_basic_type(
            "i64",
            64,
            0x07,
            #[cfg(not(feature = "llvm7-0"))]
            DIFlags::PUBLIC,
        )
        .unwrap();
    let f32ty = dibuilder
        .create_basic_type(
            "f32",
            32,
            0x04,
            #[cfg(not(feature = "llvm7-0"))]
            DIFlags::PUBLIC,
        )
        .unwrap();
    let f64ty = dibuilder
        .create_basic_type(
            "f64",
            64,
            0x04,
            #[cfg(not(feature = "llvm7-0"))]
            DIFlags::PUBLIC,
        )
        .unwrap();

    let member_sizes = vec![32, 64, 32, 64];
    let member_types = vec![i32ty, i64ty, f32ty, f64ty];
    let member_placeholders = member_types
        .iter()
        .map(|_ty| unsafe { dibuilder.create_placeholder_derived_type(&context) })
        .collect::<Vec<_>>();
    let member_placeholders_as_ditype = member_types
        .iter()
        .map(|ty| ty.as_type())
        .collect::<Vec<_>>();

    let structty = dibuilder.create_struct_type(
        compile_unit.get_file().as_debug_info_scope(),
        "",
        compile_unit.get_file(),
        0,
        192,
        8,
        DIFlags::PUBLIC,
        None,
        member_placeholders_as_ditype.as_slice(),
        0,
        None,
        "",
    );

    let mut offset = 0;
    for ((placeholder, ty), size) in member_placeholders
        .iter()
        .zip(member_types.iter())
        .zip(member_sizes.iter())
    {
        let member = dibuilder.create_member_type(
            structty.as_debug_info_scope(),
            "",
            compile_unit.get_file(),
            0,
            *size,
            8,
            offset,
            DIFlags::PUBLIC,
            ty.as_type(),
        );
        unsafe {
            dibuilder.replace_placeholder_derived_type(*placeholder, member);
        }
        offset += size;
    }

    dibuilder.finalize();

    assert!(module.verify().is_ok());
}

#[test]
fn test_no_explicit_finalize() {
    let context = Context::create();
    let module = context.create_module("");

    let (dibuilder, _compile_unit) = module.create_debug_info_builder(
        true,
        DWARFSourceLanguage::C,
        "source_file",
        ".",
        "my llvm compiler frontend",
        false,
        "",
        0,
        "",
        DWARFEmissionKind::Full,
        0,
        false,
        false,
        #[cfg(any(feature = "llvm11-0", feature = "llvm12-0"))]
        "",
        #[cfg(any(feature = "llvm11-0", feature = "llvm12-0"))]
        "",
    );

    drop(dibuilder);

    assert!(module.verify().is_ok());
}

#[llvm_versions(8.0..=latest)]
#[test]
fn test_replacing_placeholder_with_placeholder() {
    let context = Context::create();
    let module = context.create_module("");

    let (dibuilder, compile_unit) = module.create_debug_info_builder(
        true,
        DWARFSourceLanguage::C,
        "source_file",
        ".",
        "my llvm compiler frontend",
        false,
        "",
        0,
        "",
        DWARFEmissionKind::Full,
        0,
        false,
        false,
        #[cfg(any(feature = "llvm11-0", feature = "llvm12-0"))]
        "",
        #[cfg(any(feature = "llvm11-0", feature = "llvm12-0"))]
        "",
    );

    let i32ty = dibuilder
        .create_basic_type("i32", 32, 0x07, DIFlags::PUBLIC)
        .unwrap();
    let typedefty = dibuilder.create_typedef(
        i32ty.as_type(),
        "",
        compile_unit.get_file(),
        0,
        compile_unit.get_file().as_debug_info_scope(),
        #[cfg(not(any(feature = "llvm8-0", feature = "llvm9-0")))]
        32,
    );

    unsafe {
        let ph1 = dibuilder.create_placeholder_derived_type(&context);
        let ph2 = dibuilder.create_placeholder_derived_type(&context);

        dibuilder.replace_placeholder_derived_type(ph2, ph1);
        dibuilder.replace_placeholder_derived_type(ph1, typedefty);
    }
}

#[test]
fn test_anonymous_basic_type() {
    let context = Context::create();
    let module = context.create_module("bin");

    let (dibuilder, _compile_unit) = module.create_debug_info_builder(
        true,
        DWARFSourceLanguage::C,
        "source_file",
        ".",
        "my llvm compiler frontend",
        false,
        "",
        0,
        "",
        DWARFEmissionKind::Full,
        0,
        false,
        false,
        #[cfg(any(feature = "llvm11-0", feature = "llvm12-0"))]
        "",
        #[cfg(any(feature = "llvm11-0", feature = "llvm12-0"))]
        "",
    );

    assert_eq!(
        dibuilder.create_basic_type(
            "",
            0_u64,
            0x00,
            #[cfg(not(feature = "llvm7-0"))]
            DIFlags::ZERO
        ),
        Err("basic types must have names")
    );
}

#[llvm_versions(8.0..=latest)]
#[test]
fn test_global_expressions() {
    let context = Context::create();
    let module = context.create_module("bin");

    let (dibuilder, compile_unit) = module.create_debug_info_builder(
        true,
        DWARFSourceLanguage::C,
        "source_file",
        ".",
        "my llvm compiler frontend",
        false,
        "",
        0,
        "",
        DWARFEmissionKind::Full,
        0,
        false,
        false,
        #[cfg(any(feature = "llvm11-0", feature = "llvm12-0"))]
        "",
        #[cfg(any(feature = "llvm11-0", feature = "llvm12-0"))]
        "",
    );

    let di_type = dibuilder.create_basic_type("type_name", 0_u64, 0x00, DIFlags::ZERO);
    let gv = module.add_global(context.i64_type(), Some(inkwell::AddressSpace::Global), "gv");

    let const_v = dibuilder.create_constant_expression(10);

    let gv_debug = dibuilder.create_global_variable_expression(
        compile_unit.as_debug_info_scope(),
        "gv",
        "",
        compile_unit.get_file(),
        1,
        di_type.unwrap().as_type(),
        true,
        Some(const_v),
        None,
        8,
    );

    let metadata = context.metadata_node(&[gv_debug.as_metadata_value(&context).into()]);

    gv.set_metadata(metadata, 0);

    // TODO: Metadata set on the global values cannot be retrieved using the C api,
    // therefore, it's currently not possible to test that the data was set without generating the IR
    assert!(gv.print_to_string().to_string().contains("!dbg"), format!("expected !dbg but generated gv was {}",gv.print_to_string()));
}
<|endoftext|>


<commit_before>//! HIR datatypes. See the [rustc dev guide] for more info.
//!
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html

pub mod exports;
pub mod map;
pub mod place;

use crate::ty::query::Providers;
use crate::ty::TyCtxt;
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_hir::def_id::LocalDefId;
use rustc_hir::*;
use rustc_query_system::ich::StableHashingContext;
use rustc_span::DUMMY_SP;

/// Top-level HIR node for current owner. This only contains the node for which
/// `HirId::local_id == 0`, and excludes bodies.
///
/// This struct exists to encapsulate all access to the hir_owner query in this module, and to
/// implement HashStable without hashing bodies.
#[derive(Copy, Clone, Debug)]
pub struct Owner<'tcx> {
    node: OwnerNode<'tcx>,
    hash_without_bodies: Fingerprint,
}

impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Owner<'tcx> {
    #[inline]
    fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
        let Owner { node: _, hash_without_bodies } = self;
        hash_without_bodies.hash_stable(hcx, hasher)
    }
}

/// Gather the LocalDefId for each item-like within a module, including items contained within
/// bodies.  The Ids are in visitor order.  This is used to partition a pass between modules.
#[derive(Debug, HashStable)]
pub struct ModuleItems {
    submodules: Box<[LocalDefId]>,
    items: Box<[ItemId]>,
    trait_items: Box<[TraitItemId]>,
    impl_items: Box<[ImplItemId]>,
    foreign_items: Box<[ForeignItemId]>,
}

impl<'tcx> TyCtxt<'tcx> {
    #[inline(always)]
    pub fn hir(self) -> map::Map<'tcx> {
        map::Map { tcx: self }
    }

    pub fn parent_module(self, id: HirId) -> LocalDefId {
        self.parent_module_from_def_id(id.owner)
    }
}

pub fn provide(providers: &mut Providers) {
    providers.parent_module_from_def_id = |tcx, id| {
        let hir = tcx.hir();
        hir.local_def_id(hir.get_module_parent_node(hir.local_def_id_to_hir_id(id)))
    };
    providers.hir_crate = |tcx, ()| tcx.untracked_crate;
    providers.crate_hash = map::crate_hash;
    providers.hir_module_items = map::hir_module_items;
    providers.hir_owner = |tcx, id| {
        let owner = tcx.hir_crate(()).owners[id].as_ref()?;
        let node = owner.node();
        Some(Owner { node, hash_without_bodies: owner.nodes.hash_without_bodies })
    };
    providers.hir_owner_nodes = |tcx, id| tcx.hir_crate(()).owners[id].as_ref().map(|i| &i.nodes);
    providers.hir_owner_parent = |tcx, id| {
        let parent = tcx.untracked_resolutions.definitions.def_key(id).parent;
        let parent = parent.map_or(CRATE_HIR_ID, |local_def_index| {
            let def_id = LocalDefId { local_def_index };
            let mut parent_hir_id =
                tcx.untracked_resolutions.definitions.local_def_id_to_hir_id(def_id);
            if let Some(local_id) =
                tcx.hir_crate(()).owners[parent_hir_id.owner].as_ref().unwrap().parenting.get(&id)
            {
                parent_hir_id.local_id = *local_id;
            }
            parent_hir_id
        });
        parent
    };
    providers.hir_attrs =
        |tcx, id| tcx.hir_crate(()).owners[id].as_ref().map_or(AttributeMap::EMPTY, |o| &o.attrs);
    providers.source_span = |tcx, def_id| tcx.resolutions(()).definitions.def_span(def_id);
    providers.def_span = |tcx, def_id| tcx.hir().span_if_local(def_id).unwrap_or(DUMMY_SP);
    providers.fn_arg_names = |tcx, id| {
        let hir = tcx.hir();
        let hir_id = hir.local_def_id_to_hir_id(id.expect_local());
        if let Some(body_id) = hir.maybe_body_owned_by(hir_id) {
            tcx.arena.alloc_from_iter(hir.body_param_names(body_id))
        } else if let Node::TraitItem(&TraitItem {
            kind: TraitItemKind::Fn(_, TraitFn::Required(idents)),
            ..
        }) = hir.get(hir_id)
        {
            tcx.arena.alloc_slice(idents)
        } else {
            span_bug!(hir.span(hir_id), "fn_arg_names: unexpected item {:?}", id);
        }
    };
    providers.opt_def_kind = |tcx, def_id| tcx.hir().opt_def_kind(def_id.expect_local());
    providers.all_local_trait_impls = |tcx, ()| &tcx.resolutions(()).trait_impls;
    providers.expn_that_defined = |tcx, id| {
        let id = id.expect_local();
        tcx.resolutions(()).definitions.expansion_that_defined(id)
    };
}
<commit_msg>Justify untracked access.<commit_after>//! HIR datatypes. See the [rustc dev guide] for more info.
//!
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html

pub mod exports;
pub mod map;
pub mod place;

use crate::ty::query::Providers;
use crate::ty::TyCtxt;
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_hir::def_id::LocalDefId;
use rustc_hir::*;
use rustc_query_system::ich::StableHashingContext;
use rustc_span::DUMMY_SP;

/// Top-level HIR node for current owner. This only contains the node for which
/// `HirId::local_id == 0`, and excludes bodies.
///
/// This struct exists to encapsulate all access to the hir_owner query in this module, and to
/// implement HashStable without hashing bodies.
#[derive(Copy, Clone, Debug)]
pub struct Owner<'tcx> {
    node: OwnerNode<'tcx>,
    hash_without_bodies: Fingerprint,
}

impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Owner<'tcx> {
    #[inline]
    fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
        let Owner { node: _, hash_without_bodies } = self;
        hash_without_bodies.hash_stable(hcx, hasher)
    }
}

/// Gather the LocalDefId for each item-like within a module, including items contained within
/// bodies.  The Ids are in visitor order.  This is used to partition a pass between modules.
#[derive(Debug, HashStable)]
pub struct ModuleItems {
    submodules: Box<[LocalDefId]>,
    items: Box<[ItemId]>,
    trait_items: Box<[TraitItemId]>,
    impl_items: Box<[ImplItemId]>,
    foreign_items: Box<[ForeignItemId]>,
}

impl<'tcx> TyCtxt<'tcx> {
    #[inline(always)]
    pub fn hir(self) -> map::Map<'tcx> {
        map::Map { tcx: self }
    }

    pub fn parent_module(self, id: HirId) -> LocalDefId {
        self.parent_module_from_def_id(id.owner)
    }
}

pub fn provide(providers: &mut Providers) {
    providers.parent_module_from_def_id = |tcx, id| {
        let hir = tcx.hir();
        hir.local_def_id(hir.get_module_parent_node(hir.local_def_id_to_hir_id(id)))
    };
    providers.hir_crate = |tcx, ()| tcx.untracked_crate;
    providers.crate_hash = map::crate_hash;
    providers.hir_module_items = map::hir_module_items;
    providers.hir_owner = |tcx, id| {
        let owner = tcx.hir_crate(()).owners[id].as_ref()?;
        let node = owner.node();
        Some(Owner { node, hash_without_bodies: owner.nodes.hash_without_bodies })
    };
    providers.hir_owner_nodes = |tcx, id| tcx.hir_crate(()).owners[id].as_ref().map(|i| &i.nodes);
    providers.hir_owner_parent = |tcx, id| {
        // Accessing the def_key is ok since its value is hashed as part of `id`'s DefPathHash.
        let parent = tcx.untracked_resolutions.definitions.def_key(id).parent;
        let parent = parent.map_or(CRATE_HIR_ID, |local_def_index| {
            let def_id = LocalDefId { local_def_index };
            let mut parent_hir_id =
                tcx.untracked_resolutions.definitions.local_def_id_to_hir_id(def_id);
            if let Some(local_id) =
                tcx.hir_crate(()).owners[parent_hir_id.owner].as_ref().unwrap().parenting.get(&id)
            {
                parent_hir_id.local_id = *local_id;
            }
            parent_hir_id
        });
        parent
    };
    providers.hir_attrs =
        |tcx, id| tcx.hir_crate(()).owners[id].as_ref().map_or(AttributeMap::EMPTY, |o| &o.attrs);
    providers.source_span = |tcx, def_id| tcx.resolutions(()).definitions.def_span(def_id);
    providers.def_span = |tcx, def_id| tcx.hir().span_if_local(def_id).unwrap_or(DUMMY_SP);
    providers.fn_arg_names = |tcx, id| {
        let hir = tcx.hir();
        let hir_id = hir.local_def_id_to_hir_id(id.expect_local());
        if let Some(body_id) = hir.maybe_body_owned_by(hir_id) {
            tcx.arena.alloc_from_iter(hir.body_param_names(body_id))
        } else if let Node::TraitItem(&TraitItem {
            kind: TraitItemKind::Fn(_, TraitFn::Required(idents)),
            ..
        }) = hir.get(hir_id)
        {
            tcx.arena.alloc_slice(idents)
        } else {
            span_bug!(hir.span(hir_id), "fn_arg_names: unexpected item {:?}", id);
        }
    };
    providers.opt_def_kind = |tcx, def_id| tcx.hir().opt_def_kind(def_id.expect_local());
    providers.all_local_trait_impls = |tcx, ()| &tcx.resolutions(()).trait_impls;
    providers.expn_that_defined = |tcx, id| {
        let id = id.expect_local();
        tcx.resolutions(()).definitions.expansion_that_defined(id)
    };
}
<|endoftext|>


<commit_before>use super::{UpdateTarget, IncompleteUpdateStatement};
use super::delete_statement::DeleteStatement;

pub fn update<T: UpdateTarget>(source: T) -> IncompleteUpdateStatement<T> {
    IncompleteUpdateStatement::new(source)
}

pub fn delete<T: UpdateTarget>(source: T) -> DeleteStatement<T> {
    DeleteStatement::new(source)
}
<commit_msg>Document the `delete` function.<commit_after>use super::{UpdateTarget, IncompleteUpdateStatement};
use super::delete_statement::DeleteStatement;

pub fn update<T: UpdateTarget>(source: T) -> IncompleteUpdateStatement<T> {
    IncompleteUpdateStatement::new(source)
}

/// Creates a delete statement. Will delete the records in the given set.
/// Because this function has a very generic name, it is not exported by
/// default.
///
/// # Examples
///
/// ### Deleting a single record:
///
/// ```rust
/// # #[macro_use] extern crate yaqb;
/// # include!("src/doctest_setup.rs");
/// #
/// # table! {
/// #     users {
/// #         id -> Serial,
/// #         name -> VarChar,
/// #     }
/// # }
/// #
/// # fn main() {
/// #     use self::users::dsl::*;
/// #     use yaqb::query_builder::delete;
/// #     let connection = establish_connection();
/// #     let get_count = || users.count().first::<i64>(&connection).unwrap().unwrap();
/// let old_count = get_count();
/// let command = delete(users.filter(id.eq(1)));
/// connection.execute_returning_count(&command).unwrap();
/// assert_eq!(old_count - 1, get_count());
/// # }
/// ```
///
/// ### Deleting a whole table:
///
/// ```rust
/// # #[macro_use] extern crate yaqb;
/// # include!("src/doctest_setup.rs");
/// #
/// # table! {
/// #     users {
/// #         id -> Serial,
/// #         name -> VarChar,
/// #     }
/// # }
/// #
/// # fn main() {
/// #     use self::users::dsl::*;
/// #     use yaqb::query_builder::delete;
/// #     let connection = establish_connection();
/// #     let get_count = || users.count().first::<i64>(&connection).unwrap().unwrap();
/// connection.execute_returning_count(&delete(users)).unwrap();
/// assert_eq!(0, get_count());
/// # }
/// ```
pub fn delete<T: UpdateTarget>(source: T) -> DeleteStatement<T> {
    DeleteStatement::new(source)
}
<|endoftext|>


<commit_before>use rayon::prelude::*;
use ssz::{SignedRoot, TreeHash};
use types::{
    attester_slashing::AttesterSlashingBuilder,
    proposer_slashing::ProposerSlashingBuilder,
    test_utils::{
        TestingAttestationBuilder, TestingDepositBuilder, TestingTransferBuilder,
        TestingVoluntaryExitBuilder,
    },
    *,
};

pub struct BeaconBlockBencher {
    block: BeaconBlock,
}

impl BeaconBlockBencher {
    pub fn new(spec: &ChainSpec) -> Self {
        Self {
            block: BeaconBlock::genesis(spec.zero_hash, spec),
        }
    }

    pub fn set_slot(&mut self, slot: Slot) {
        self.block.slot = slot;
    }

    /// Signs the block.
    pub fn sign(&mut self, sk: &SecretKey, fork: &Fork, spec: &ChainSpec) {
        let proposal = self.block.proposal(spec);
        let message = proposal.signed_root();
        let epoch = self.block.slot.epoch(spec.slots_per_epoch);
        let domain = spec.get_domain(epoch, Domain::Proposal, fork);
        self.block.signature = Signature::new(&message, domain, sk);
    }

    /// Sets the randao to be a signature across the blocks epoch.
    pub fn set_randao_reveal(&mut self, sk: &SecretKey, fork: &Fork, spec: &ChainSpec) {
        let epoch = self.block.slot.epoch(spec.slots_per_epoch);
        let message = epoch.hash_tree_root();
        let domain = spec.get_domain(epoch, Domain::Randao, fork);
        self.block.randao_reveal = Signature::new(&message, domain, sk);
    }

    /// Inserts a signed, valid `ProposerSlashing` for the validator.
    pub fn insert_proposer_slashing(
        &mut self,
        validator_index: u64,
        secret_key: &SecretKey,
        fork: &Fork,
        spec: &ChainSpec,
    ) {
        let proposer_slashing = build_proposer_slashing(validator_index, secret_key, fork, spec);
        self.block.body.proposer_slashings.push(proposer_slashing);
    }

    /// Inserts a signed, valid `AttesterSlashing` for each validator index in `validator_indices`.
    pub fn insert_attester_slashing(
        &mut self,
        validator_indices: &[u64],
        secret_keys: &[&SecretKey],
        fork: &Fork,
        spec: &ChainSpec,
    ) {
        let attester_slashing =
            build_double_vote_attester_slashing(validator_indices, secret_keys, fork, spec);
        self.block.body.attester_slashings.push(attester_slashing);
    }

    /// Fills the block with as many attestations as possible.
    ///
    /// Note: this will not perform well when `jepoch_committees_count % slots_per_epoch != 0`
    pub fn fill_with_attestations(
        &mut self,
        state: &BeaconState,
        secret_keys: &[&SecretKey],
        spec: &ChainSpec,
    ) -> Result<(), BeaconStateError> {
        let mut slot = self.block.slot - spec.min_attestation_inclusion_delay;
        let mut attestations_added = 0;

        // Stores the following (in order):
        //
        // - The slot of the committee.
        // - A list of all validators in the committee.
        // - A list of all validators in the committee that should sign the attestation.
        // - The shard of the committee.
        let mut committees: Vec<(Slot, Vec<usize>, Vec<usize>, u64)> = vec![];

        // Loop backwards through slots gathering each committee, until:
        //
        // - The slot is too old to be included in a block at this slot.
        // - The `MAX_ATTESTATIONS`.
        loop {
            if attestations_added == spec.max_attestations {
                break;
            }
            if state.slot >= slot + spec.slots_per_epoch {
                break;
            }

            for (committee, shard) in state.get_crosslink_committees_at_slot(slot, spec)? {
                committees.push((slot, committee.clone(), committee.clone(), *shard))
            }

            attestations_added += 1;
            slot -= 1;
        }

        // Loop through all the committees, splitting each one in half until we have
        // `MAX_ATTESTATIONS` committees.
        loop {
            if committees.len() >= spec.max_attestations as usize {
                break;
            }

            for index in 0..committees.len() {
                if committees.len() >= spec.max_attestations as usize {
                    break;
                }

                let (slot, committee, mut signing_validators, shard) = committees[index].clone();

                let new_signing_validators =
                    signing_validators.split_off(signing_validators.len() / 2);

                committees[index] = (slot, committee.clone(), signing_validators, shard);
                committees.push((slot, committee, new_signing_validators, shard));
            }
        }

        let mut attestations: Vec<Attestation> = committees
            .par_iter()
            .map(|(slot, committee, signing_validators, shard)| {
                let mut builder =
                    TestingAttestationBuilder::new(state, committee, *slot, *shard, spec);

                let signing_secret_keys: Vec<&SecretKey> = signing_validators
                    .iter()
                    .map(|validator_index| secret_keys[*validator_index])
                    .collect();
                builder.sign(signing_validators, &signing_secret_keys, &state.fork, spec);

                builder.build()
            })
            .collect();

        self.block.body.attestations.append(&mut attestations);

        Ok(())
    }

    /// Insert a `Valid` deposit into the state.
    pub fn insert_deposit(&mut self, amount: u64, index: u64, spec: &ChainSpec) {
        let keypair = Keypair::random();

        let mut builder = TestingDepositBuilder::new(amount);
        builder.set_index(index);
        builder.sign(&keypair, spec);

        self.block.body.deposits.push(builder.build())
    }

    /// Insert a `Valid` exit into the state.
    pub fn insert_exit(
        &mut self,
        state: &BeaconState,
        validator_index: u64,
        secret_key: &SecretKey,
        spec: &ChainSpec,
    ) {
        let mut builder = TestingVoluntaryExitBuilder::new(
            state.slot.epoch(spec.slots_per_epoch),
            validator_index,
        );

        builder.sign(secret_key, &state.fork, spec);

        self.block.body.voluntary_exits.push(builder.build())
    }

    /// Insert a `Valid` transfer into the state.
    ///
    /// Note: this will set the validator to be withdrawable by directly modifying the state
    /// validator registry. This _may_ cause problems historic hashes, etc.
    pub fn insert_transfer(
        &mut self,
        state: &BeaconState,
        from: u64,
        to: u64,
        amount: u64,
        keypair: Keypair,
        spec: &ChainSpec,
    ) {
        let mut builder = TestingTransferBuilder::new(from, to, amount, state.slot);
        builder.sign(keypair, &state.fork, spec);

        self.block.body.transfers.push(builder.build())
    }

    /// Signs and returns the block, consuming the builder.
    pub fn build(mut self, sk: &SecretKey, fork: &Fork, spec: &ChainSpec) -> BeaconBlock {
        self.sign(sk, fork, spec);
        self.block
    }

    /// Returns the block, consuming the builder.
    pub fn build_without_signing(self) -> BeaconBlock {
        self.block
    }
}

/// Builds an `ProposerSlashing` for some `validator_index`.
///
/// Signs the message using a `BeaconChainHarness`.
fn build_proposer_slashing(
    validator_index: u64,
    secret_key: &SecretKey,
    fork: &Fork,
    spec: &ChainSpec,
) -> ProposerSlashing {
    let signer = |_validator_index: u64, message: &[u8], epoch: Epoch, domain: Domain| {
        let domain = spec.get_domain(epoch, domain, fork);
        Signature::new(message, domain, secret_key)
    };

    ProposerSlashingBuilder::double_vote(validator_index, signer, spec)
}

/// Builds an `AttesterSlashing` for some `validator_indices`.
///
/// Signs the message using a `BeaconChainHarness`.
fn build_double_vote_attester_slashing(
    validator_indices: &[u64],
    secret_keys: &[&SecretKey],
    fork: &Fork,
    spec: &ChainSpec,
) -> AttesterSlashing {
    let signer = |validator_index: u64, message: &[u8], epoch: Epoch, domain: Domain| {
        let key_index = validator_indices
            .iter()
            .position(|&i| i == validator_index)
            .expect("Unable to find attester slashing key");
        let domain = spec.get_domain(epoch, domain, fork);
        Signature::new(message, domain, secret_keys[key_index])
    };

    AttesterSlashingBuilder::double_vote(validator_indices, signer)
}
<commit_msg>Fix attestations bug in block builder.<commit_after>use rayon::prelude::*;
use ssz::{SignedRoot, TreeHash};
use types::{
    attester_slashing::AttesterSlashingBuilder,
    proposer_slashing::ProposerSlashingBuilder,
    test_utils::{
        TestingAttestationBuilder, TestingDepositBuilder, TestingTransferBuilder,
        TestingVoluntaryExitBuilder,
    },
    *,
};

pub struct BeaconBlockBencher {
    block: BeaconBlock,
}

impl BeaconBlockBencher {
    pub fn new(spec: &ChainSpec) -> Self {
        Self {
            block: BeaconBlock::genesis(spec.zero_hash, spec),
        }
    }

    pub fn set_slot(&mut self, slot: Slot) {
        self.block.slot = slot;
    }

    /// Signs the block.
    pub fn sign(&mut self, sk: &SecretKey, fork: &Fork, spec: &ChainSpec) {
        let proposal = self.block.proposal(spec);
        let message = proposal.signed_root();
        let epoch = self.block.slot.epoch(spec.slots_per_epoch);
        let domain = spec.get_domain(epoch, Domain::Proposal, fork);
        self.block.signature = Signature::new(&message, domain, sk);
    }

    /// Sets the randao to be a signature across the blocks epoch.
    pub fn set_randao_reveal(&mut self, sk: &SecretKey, fork: &Fork, spec: &ChainSpec) {
        let epoch = self.block.slot.epoch(spec.slots_per_epoch);
        let message = epoch.hash_tree_root();
        let domain = spec.get_domain(epoch, Domain::Randao, fork);
        self.block.randao_reveal = Signature::new(&message, domain, sk);
    }

    /// Inserts a signed, valid `ProposerSlashing` for the validator.
    pub fn insert_proposer_slashing(
        &mut self,
        validator_index: u64,
        secret_key: &SecretKey,
        fork: &Fork,
        spec: &ChainSpec,
    ) {
        let proposer_slashing = build_proposer_slashing(validator_index, secret_key, fork, spec);
        self.block.body.proposer_slashings.push(proposer_slashing);
    }

    /// Inserts a signed, valid `AttesterSlashing` for each validator index in `validator_indices`.
    pub fn insert_attester_slashing(
        &mut self,
        validator_indices: &[u64],
        secret_keys: &[&SecretKey],
        fork: &Fork,
        spec: &ChainSpec,
    ) {
        let attester_slashing =
            build_double_vote_attester_slashing(validator_indices, secret_keys, fork, spec);
        self.block.body.attester_slashings.push(attester_slashing);
    }

    /// Fills the block with as many attestations as possible.
    ///
    /// Note: this will not perform well when `jepoch_committees_count % slots_per_epoch != 0`
    pub fn fill_with_attestations(
        &mut self,
        state: &BeaconState,
        secret_keys: &[&SecretKey],
        spec: &ChainSpec,
    ) -> Result<(), BeaconStateError> {
        let mut slot = self.block.slot - spec.min_attestation_inclusion_delay;
        let mut attestations_added = 0;

        // Stores the following (in order):
        //
        // - The slot of the committee.
        // - A list of all validators in the committee.
        // - A list of all validators in the committee that should sign the attestation.
        // - The shard of the committee.
        let mut committees: Vec<(Slot, Vec<usize>, Vec<usize>, u64)> = vec![];

        // Loop backwards through slots gathering each committee, until:
        //
        // - The slot is too old to be included in a block at this slot.
        // - The `MAX_ATTESTATIONS`.
        loop {
            if state.slot >= slot + spec.slots_per_epoch {
                break;
            }

            for (committee, shard) in state.get_crosslink_committees_at_slot(slot, spec)? {
                if attestations_added >= spec.max_attestations {
                    break;
                }

                committees.push((slot, committee.clone(), committee.clone(), *shard));

                attestations_added += 1;
            }

            slot -= 1;
        }

        // Loop through all the committees, splitting each one in half until we have
        // `MAX_ATTESTATIONS` committees.
        loop {
            if committees.len() >= spec.max_attestations as usize {
                break;
            }

            for index in 0..committees.len() {
                if committees.len() >= spec.max_attestations as usize {
                    break;
                }

                let (slot, committee, mut signing_validators, shard) = committees[index].clone();

                let new_signing_validators =
                    signing_validators.split_off(signing_validators.len() / 2);

                committees[index] = (slot, committee.clone(), signing_validators, shard);
                committees.push((slot, committee, new_signing_validators, shard));
            }
        }

        let mut attestations: Vec<Attestation> = committees
            .par_iter()
            .map(|(slot, committee, signing_validators, shard)| {
                let mut builder =
                    TestingAttestationBuilder::new(state, committee, *slot, *shard, spec);

                let signing_secret_keys: Vec<&SecretKey> = signing_validators
                    .iter()
                    .map(|validator_index| secret_keys[*validator_index])
                    .collect();
                builder.sign(signing_validators, &signing_secret_keys, &state.fork, spec);

                builder.build()
            })
            .collect();

        self.block.body.attestations.append(&mut attestations);

        Ok(())
    }

    /// Insert a `Valid` deposit into the state.
    pub fn insert_deposit(&mut self, amount: u64, index: u64, spec: &ChainSpec) {
        let keypair = Keypair::random();

        let mut builder = TestingDepositBuilder::new(amount);
        builder.set_index(index);
        builder.sign(&keypair, spec);

        self.block.body.deposits.push(builder.build())
    }

    /// Insert a `Valid` exit into the state.
    pub fn insert_exit(
        &mut self,
        state: &BeaconState,
        validator_index: u64,
        secret_key: &SecretKey,
        spec: &ChainSpec,
    ) {
        let mut builder = TestingVoluntaryExitBuilder::new(
            state.slot.epoch(spec.slots_per_epoch),
            validator_index,
        );

        builder.sign(secret_key, &state.fork, spec);

        self.block.body.voluntary_exits.push(builder.build())
    }

    /// Insert a `Valid` transfer into the state.
    ///
    /// Note: this will set the validator to be withdrawable by directly modifying the state
    /// validator registry. This _may_ cause problems historic hashes, etc.
    pub fn insert_transfer(
        &mut self,
        state: &BeaconState,
        from: u64,
        to: u64,
        amount: u64,
        keypair: Keypair,
        spec: &ChainSpec,
    ) {
        let mut builder = TestingTransferBuilder::new(from, to, amount, state.slot);
        builder.sign(keypair, &state.fork, spec);

        self.block.body.transfers.push(builder.build())
    }

    /// Signs and returns the block, consuming the builder.
    pub fn build(mut self, sk: &SecretKey, fork: &Fork, spec: &ChainSpec) -> BeaconBlock {
        self.sign(sk, fork, spec);
        self.block
    }

    /// Returns the block, consuming the builder.
    pub fn build_without_signing(self) -> BeaconBlock {
        self.block
    }
}

/// Builds an `ProposerSlashing` for some `validator_index`.
///
/// Signs the message using a `BeaconChainHarness`.
fn build_proposer_slashing(
    validator_index: u64,
    secret_key: &SecretKey,
    fork: &Fork,
    spec: &ChainSpec,
) -> ProposerSlashing {
    let signer = |_validator_index: u64, message: &[u8], epoch: Epoch, domain: Domain| {
        let domain = spec.get_domain(epoch, domain, fork);
        Signature::new(message, domain, secret_key)
    };

    ProposerSlashingBuilder::double_vote(validator_index, signer, spec)
}

/// Builds an `AttesterSlashing` for some `validator_indices`.
///
/// Signs the message using a `BeaconChainHarness`.
fn build_double_vote_attester_slashing(
    validator_indices: &[u64],
    secret_keys: &[&SecretKey],
    fork: &Fork,
    spec: &ChainSpec,
) -> AttesterSlashing {
    let signer = |validator_index: u64, message: &[u8], epoch: Epoch, domain: Domain| {
        let key_index = validator_indices
            .iter()
            .position(|&i| i == validator_index)
            .expect("Unable to find attester slashing key");
        let domain = spec.get_domain(epoch, domain, fork);
        Signature::new(message, domain, secret_keys[key_index])
    };

    AttesterSlashingBuilder::double_vote(validator_indices, signer)
}
<|endoftext|>