1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
// Testing the formatting of constant values (i.e. evaluated constant expressions)
// where the specific format was first proposed in issue #98929.

// edition:2021
//#![crate_name = "consts"]

// aux-build:const-value.rs
// build-aux-docs
// ignore-cross-compile
//extern crate const_value as aux;

// ignore-tidy-linelength

// FIXME: Some tests in here might be redundant and already present in other test files.
// FIXME: Test restricted visibilities (e.g. `pub(super)`, `pub(in crate::some::thing)`).

// Check that constant expressions are printed in their evaluated form.
//
// @has 'consts/constant.HOUR_IN_SECONDS.html'
// @has - '//*[@class="docblock item-decl"]//code' 'pub const HOUR_IN_SECONDS: u64 = 3600;'
pub const HOUR_IN_SECONDS: u64 = 60 * 60;

// @has 'consts/constant.NEGATIVE.html'
// @has - '//*[@class="docblock item-decl"]//code' 'pub const NEGATIVE: i64 = -3600;'
pub const NEGATIVE: i64 = -60 * 60;

// @has 'consts/constant.CONCATENATED.html'
// @has - '//*[@class="docblock item-decl"]//code' \
//        "pub const CONCATENATED: &'static str = \"[0, +∞)\";"
pub const CONCATENATED: &str = concat!("[", stringify!(0), ", ", "+∞", ")");

// @has 'consts/struct.Record.html'
pub struct Record<'r> {
    pub one: &'r str,
    pub two: (i32,),
}

// Test that structs whose fields are all public and 1-tuples are displayed correctly.
// Furthermore, the struct fields should appear in definition order.
// Re snapshot: Check that hyperlinks are generated for the struct name and fields.
//
// @has 'consts/constant.REC.html'
// @has - '//*[@class="docblock item-decl"]//code' \
//        "const REC: Record<'static> = Record { one: \"thriving\", two: (180,) }"
// @snapshot rec - '//*[@class="docblock item-decl"]//code'
pub const REC: Record<'_> = {
    assert!(true);

    let auxiliary = 90 * "||".len() as i32;
    Record {
        two: (
            auxiliary,
            #[cfg(FALSE)]
            "vanished",
        ),
        one: "thriving",
    }
};

// Check that private and doc(hidden) struct fields are not displayed.
// Instead, an ellipsis (namely `..`) should be printed.
// Re snapshot: Check that hyperlinks are generated for the struct name and the public struct field.
//
// @has 'consts/constant.STRUCT.html'
// @has - '//*[@class="docblock item-decl"]//code' \
//        'const STRUCT: Struct = Struct { public: (), .. }'
// @snapshot struct - '//*[@class="docblock item-decl"]//code'
pub const STRUCT: Struct = Struct {
    private : /* SourceMap::span_to_snippet trap */ (),
    public: { 1 + 3; },
    hidden: ()
};

// Test that enum variants, 2-tuples, bools and structs (with private and doc(hidden) fields) nested
// within are rendered correctly. Further, check that there is a maximum depth.
// Re snapshot: Test the hyperlinks are generated for the cross-crate enum variant etc.
//
// @has 'consts/constant.NESTED.html'
// @has - '//*[@class="docblock item-decl"]//code' \
//        'const NESTED: Option<(Struct, bool)> = Some((Struct { public: …, .. }, false))'
// @snapshot nested - '//*[@class="docblock item-decl"]//code'
pub const NESTED: Option<(Struct, bool)> = Some((
    Struct {
        public: (),
        private: (),
        hidden: (),
    },
    false,
));

use std::sync::atomic::AtomicBool;

// @has 'consts/struct.Struct.html'
pub struct Struct {
    private: (),
    pub public: (),
    #[doc(hidden)]
    pub hidden: (),
}

impl Struct {
    // Check that even inside inherent impl blocks private and doc(hidden) struct fields
    // are not displayed.
    // Re snapshot: Check that hyperlinks are generated for the struct name and
    // the public struct field.
    //
    // @has - '//*[@id="associatedconstant.SELF"]' \
    //        'const SELF: Self = Struct { public: (), .. }'
    // @snapshot self - '//*[@id="associatedconstant.SELF"]//*[@class="code-header"]'
    pub const SELF: Self = Self {
        private: (),
        public: match () {
            () => {}
        },
        hidden: (),
    };

    // Verify that private and doc(hidden) *tuple* struct fields are not shown.
    // In their place, an underscore should be rendered.
    // Re snapshot: Check that a hyperlink is generated for the tuple struct name.
    //
    // @has - '//*[@id="associatedconstant.TUP_STRUCT"]' \
    //        'const TUP_STRUCT: TupStruct = TupStruct(_, -45, _, _)'
    // @snapshot tup-struct - '//*[@id="associatedconstant.TUP_STRUCT"]//*[@class="code-header"]'
    pub const TUP_STRUCT: TupStruct = TupStruct((), -45, (), false);

    // Check that structs whose fields are all doc(hidden) are rendered correctly.
    //
    // @has - '//*[@id="associatedconstant.SEALED0"]' \
    //        'const SEALED0: Container0 = Container0 { .. }'
    pub const SEALED0: Container0 = Container0 { hack: () };

    // Check that *tuple* structs whose fields are all private are rendered correctly.
    //
    // @has - '//*[@id="associatedconstant.SEALED1"]' \
    //        'const SEALED1: Container1 = Container1(_)'
    pub const SEALED1: Container1 = Container1(None);

    // Verify that cross-crate structs are displayed correctly and that their fields
    // are not leaked.
    // Re snapshot: Check that a hyperlink is generated for the name of the cross-crate struct.
    //
    // @has - '//*[@id="associatedconstant.SEALED2"]' \
    //        'const SEALED2: AtomicBool = AtomicBool { .. }'
    // @snapshot sealed2 - '//*[@id="associatedconstant.SEALED2"]//*[@class="code-header"]'
    pub const SEALED2: AtomicBool = AtomicBool::new(true);

    // Test that (local) *unit* enum variants are rendered properly.
    // Re snapshot: Test that a hyperlink is generated for the variant.
    //
    // @has - '//*[@id="associatedconstant.SUM0"]' \
    //        'const SUM0: Size = Uninhabited'
    // @snapshot sum0 - '//*[@id="associatedconstant.SUM0"]//*[@class="code-header"]'
    pub const SUM0: Size = self::Size::Uninhabited;

    // Test that (local) *struct* enum variants are rendered properly.
    // Re snapshot: Test that a hyperlink is generated for the variant.
    //
    // @has - '//*[@id="associatedconstant.SUM1"]' \
    //        'const SUM1: Size = Inhabited { inhabitants: 9000 }'
    // @snapshot sum1 - '//*[@id="associatedconstant.SUM1"]//*[@class="code-header"]'
    pub const SUM1: Size = AdtSize::Inhabited { inhabitants: 9_000 };

    // Test that (local) *tuple* enum variants are rendered properly.
    // Re snapshot: Test that a hyperlink is generated for the variant.
    //
    // @has - '//*[@id="associatedconstant.SUM2"]' \
    //        'const SUM2: Size = Unknown(Reason)'
    // @snapshot sum2 - '//*[@id="associatedconstant.SUM2"]//*[@class="code-header"]'
    pub const SUM2: Size = Size::Unknown(Reason);

    // @has - '//*[@id="associatedconstant.INT"]' \
    //        'const INT: i64 = 2368'
    pub const INT: i64 = 2345 + 23;

    // @has - '//*[@id="associatedconstant.STR"]' \
    //        "const STR: &'static str = \"hello friends\""
    pub const STR: &'static str = "hello friends";

    // @has - '//*[@id="associatedconstant.FLOAT0"]' \
    //        'const FLOAT0: f32 = 2930.21997'
    pub const FLOAT0: f32 = 2930.21997;

    // @has - '//*[@id="associatedconstant.FLOAT1"]' \
    //        'const FLOAT1: f64 = -3.42E+21'
    pub const FLOAT1: f64 = -3.42e+21;

    // @has - '//*[@id="associatedconstant.REF"]' \
    //        "const REF: &'static i32 = _"
    pub const REF: &'static i32 = &234;

    // @has - '//*[@id="associatedconstant.PTR"]' \
    //        'const PTR: *const u16 = _'
    pub const PTR: *const u16 = &90;

    // @has - '//*[@id="associatedconstant.ARR0"]' \
    //        'const ARR0: [u16; 8] = [1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080]'
    pub const ARR0: [u16; 8] = [12 * 90; 8];

    // Check that after a certain unspecified size threshold, array elements
    // won't be displayed anymore and that instead a *styled* series of ellipses is shown.
    // Re snapshot: Check that the series of ellipses is styled (has a certain CSS class).
    //
    // @has - '//*[@id="associatedconstant.ARR1"]' \
    //        'const ARR1: [u16; 100] = [………]'
    // @snapshot arr1 - '//*[@id="associatedconstant.ARR1"]//*[@class="code-header"]'
    pub const ARR1: [u16; 100] = [12; 52 + 50 - 2];

    // FIXME: We actually want to print the contents of slices!
    // @has - '//*[@id="associatedconstant.SLICE0"]' \
    //        "const SLICE0: &'static [bool] = _"
    pub const SLICE0: &'static [bool] = &[false, !true, true];

    //
    // The following two test cases are regression tests for issue #99630:
    // Make sure that we don't leak private and doc(hidden) struct fields
    // of cross-crate structs (i.e. structs from external crates).
    //

    // @has - '//*[@id="associatedconstant.DATA"]' \
    //        'const DATA: Data = Data { open: (0, 0, 1), .. }'
    // @snapshot data - '//*[@id="associatedconstant.DATA"]//*[@class="code-header"]'
    pub const DATA: aux::Data = aux::Data::new((0, 0, 1));

    // @has - '//*[@id="associatedconstant.OPAQ"]' \
    //        'const OPAQ: Opaque = Opaque(_)'
    // @snapshot opaq - '//*[@id="associatedconstant.OPAQ"]//*[@class="code-header"]'
    pub const OPAQ: aux::Opaque = aux::Opaque::new(0xff00);
}

pub struct TupStruct(#[doc(hidden)] pub (), pub i32, (), #[doc(hidden)] pub bool);

pub struct Container0 {
    #[doc(hidden)]
    pub hack: (),
}

pub struct Container1(Option<std::cell::Cell<u8>>);

pub type AdtSize = Size;

pub enum Size {
    Inhabited { inhabitants: u128 },
    Uninhabited,
    Unknown(Reason),
}

pub struct Reason;

use std::cmp::Ordering;

// @has 'consts/trait.Protocol.html'
pub trait Protocol {
    // Make sure that this formatting also applies to const exprs inside of trait items, not just
    // inside of inherent impl blocks or free constants.

    // @has - '//*[@id="associatedconstant.MATCH"]' \
    //        'const MATCH: u64 = 99'
    const MATCH: u64 = match 1 + 4 {
        SUPPORT => 99,
        _ => 0,
    };

    // Re snapshot: Verify that hyperlinks are created.
    //
    // @has - '//*[@id="associatedconstant.OPT"]' \
    //        'const OPT: Option<Option<Ordering>> = Some(Some(Equal))'
    // @snapshot opt - '//*[@id="associatedconstant.OPT"]//*[@class="code-header"]'
    const OPT: Option<Option<Ordering>> = Some(Some(Ordering::Equal));

    // Test that there is a depth limit. Subexpressions exceeding the maximum depth are
    // rendered as *styled* ellipses.
    // Re snapshot: Check that the ellipses are styled (have a certain CSS class).
    //
    // @has - '//*[@id="associatedconstant.DEEP0"]' \
    //        'const DEEP0: Option<Option<Option<Ordering>>> = Some(Some(Some(…)))'
    // @snapshot deep0 - '//*[@id="associatedconstant.DEEP0"]//*[@class="code-header"]'
    const DEEP0: Option<Option<Option<Ordering>>> = Some(Some(Some(Ordering::Equal)));

    // FIXME: Add more depth tests

    // @has - '//*[@id="associatedconstant.STR0"]' \
    //        "const STR0: &'static str = \"I want to <em>escape</em>!\""
    const STR0: &'static str = "I want to <em>escape</em>!";

    // Check that after a certain unspecified size threshold, the string contents
    // won't be displayed anymore and that instead a *styled* series of ellipses is shown.
    // Re snapshot: Check that the series of ellipses is styled (has a certain CSS class).
    //
    // @has - '//*[@id="associatedconstant.STR1"]' \
    //        "const STR1: &'static str = \"………\""
    // @snapshot str1 - '//*[@id="associatedconstant.STR1"]//*[@class="code-header"]'
    const STR1: &'static str = "\
        This is the start of a relatively long text. \
        I might as well throw some more words into it. \
        Informative content? Never heard of it! \
        That's probably one of the reasons why I shouldn't be included \
        into the generated documentation, don't you think so, too?\
    ";

    // @has - '//*[@id="associatedconstant.BYTE_STR0"]' \
    //        "const BYTE_STR0: &'static [u8] = b\"I want to <em>escape</em>!\""
    const BYTE_STR0: &'static [u8] = b"I want to <em>escape</em>!";

    // Check that after a certain unspecified size threshold, the byte string contents
    // won't be displayed anymore and that instead a *styled* series of ellipses is shown.
    // Re snapshot: Check that the series of ellipses is styled (has a certain CSS class).
    //
    // @has - '//*[@id="associatedconstant.BYTE_STR1"]' \
    //        "const BYTE_STR1: &'static [u8] = b\"………\""
    // @snapshot byte-str1 - '//*[@id="associatedconstant.BYTE_STR1"]//*[@class="code-header"]'
    const BYTE_STR1: &'static [u8] = b"\
        AGTC CCTG GAAT TACC AAAA AACA TCCA AGTC CTCT \
        AGTC CCTG TCCA AGTC CTCT GAAT TACC AAAA AACA \
        AGTC CCTG GAAT TACC AAAA GGGG GGGG AGTC GTTT \
        GGGG AACA TCCA AGTC CTCT AGTC CCTG GAAT TACC \
        AGTC AAAA GAAT TACC CGAG AACA TCCA AGTC CTCT \
        AGTC CCTG GAAT TACC TTCC AACA TCCA AGTC CTCT\
    ";

    // @has - '//*[@id="associatedconstant.BYTE_ARR0"]' \
    //        'const BYTE_ARR0: [u8; 12] = *b"DEREFERENCED"'
    const BYTE_ARR0: [u8; 12] = *b"DEREFERENCED";

    // @has - '//*[@id="associatedconstant.BYTE_ARR1"]' \
    //        "const BYTE_ARR1: [u8; 7] = *b\"MINCED\\x00\""
    const BYTE_ARR1: [u8; 7] = [b'M', b'I', b'N', b'C', b'E', b'D', b'\0'];
}

const SUPPORT: i32 = 5;

pub mod exhaustiveness {
    // @has 'consts/exhaustiveness/constant.EXHAUSTIVE_UNIT_STRUCT.html'
    // @has - '//*[@class="docblock item-decl"]//code' \
    //        'const EXHAUSTIVE_UNIT_STRUCT: ExhaustiveUnitStruct = ExhaustiveUnitStruct'
    pub const EXHAUSTIVE_UNIT_STRUCT: ExhaustiveUnitStruct = ExhaustiveUnitStruct;

    // @has 'consts/exhaustiveness/constant.EXHAUSTIVE_TUPLE_STRUCT.html'
    // @has - '//*[@class="docblock item-decl"]//code' \
    //        'const EXHAUSTIVE_TUPLE_STRUCT: ExhaustiveTupleStruct = ExhaustiveTupleStruct(())'
    pub const EXHAUSTIVE_TUPLE_STRUCT: ExhaustiveTupleStruct = ExhaustiveTupleStruct(());

    // @has 'consts/exhaustiveness/constant.EXHAUSTIVE_STRUCT.html'
    // @has - '//*[@class="docblock item-decl"]//code' \
    //        'const EXHAUSTIVE_STRUCT: ExhaustiveStruct = ExhaustiveStruct { inner: () }'
    pub const EXHAUSTIVE_STRUCT: ExhaustiveStruct = ExhaustiveStruct { inner: () };

    // @has 'consts/exhaustiveness/constant.NON_EXHAUSTIVE_UNIT_STRUCT.html'
    // @has - '//*[@class="docblock item-decl"]//code' \
    //        'const NON_EXHAUSTIVE_UNIT_STRUCT: NonExhaustiveUnitStruct = NonExhaustiveUnitStruct { .. }'
    pub const NON_EXHAUSTIVE_UNIT_STRUCT: NonExhaustiveUnitStruct = NonExhaustiveUnitStruct;

    // @has 'consts/exhaustiveness/constant.NON_EXHAUSTIVE_TUPLE_STRUCT.html'
    // @has - '//*[@class="docblock item-decl"]//code' \
    //        'const NON_EXHAUSTIVE_TUPLE_STRUCT: NonExhaustiveTupleStruct = NonExhaustiveTupleStruct((), ..)'
    pub const NON_EXHAUSTIVE_TUPLE_STRUCT: NonExhaustiveTupleStruct = NonExhaustiveTupleStruct(());

    // @has 'consts/exhaustiveness/constant.NON_EXHAUSTIVE_STRUCT.html'
    // @has - '//*[@class="docblock item-decl"]//code' \
    //        'const NON_EXHAUSTIVE_STRUCT: NonExhaustiveStruct = NonExhaustiveStruct { inner: (), .. }'
    pub const NON_EXHAUSTIVE_STRUCT: NonExhaustiveStruct = NonExhaustiveStruct { inner: () };

    // Assert that full ranges are literally rendered as `RangeFull` and not `..` to make sure that
    // `..` unambiguously means “omitted fields” in our pseudo-Rust expression syntax.
    // See the comment in `render_const_value` for more details.
    //
    // @has 'consts/exhaustiveness/constant.RANGE_FULL.html'
    // @has - '//*[@class="docblock item-decl"]//code' \
    //        'const RANGE_FULL: RangeFull = RangeFull'
    pub const RANGE_FULL: std::ops::RangeFull = ..;

    pub struct ExhaustiveUnitStruct;
    pub struct ExhaustiveTupleStruct(pub ());
    pub struct ExhaustiveStruct { pub inner: () }
    #[non_exhaustive] pub struct NonExhaustiveUnitStruct;
    #[non_exhaustive] pub struct NonExhaustiveTupleStruct(pub ());
    #[non_exhaustive] pub struct NonExhaustiveStruct { pub inner: () }
}