]> git.proxmox.com Git - rustc.git/blob - src/librustdoc/clean/cfg.rs
New upstream version 1.23.0+dfsg1
[rustc.git] / src / librustdoc / clean / cfg.rs
1 // Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! Representation of a `#[doc(cfg(...))]` attribute.
12
13 // FIXME: Once RFC #1868 is implemented, switch to use those structures instead.
14
15 use std::mem;
16 use std::fmt::{self, Write};
17 use std::ops;
18 #[cfg(stage0)]
19 use std::ascii::AsciiExt;
20
21 use syntax::symbol::Symbol;
22 use syntax::ast::{MetaItem, MetaItemKind, NestedMetaItem, NestedMetaItemKind, LitKind};
23 use syntax::parse::ParseSess;
24 use syntax::feature_gate::Features;
25
26 use syntax_pos::Span;
27
28 use html::escape::Escape;
29
30 #[derive(Clone, RustcEncodable, RustcDecodable, Debug, PartialEq)]
31 pub enum Cfg {
32 /// Accepts all configurations.
33 True,
34 /// Denies all configurations.
35 False,
36 /// A generic configration option, e.g. `test` or `target_os = "linux"`.
37 Cfg(Symbol, Option<Symbol>),
38 /// Negate a configuration requirement, i.e. `not(x)`.
39 Not(Box<Cfg>),
40 /// Union of a list of configuration requirements, i.e. `any(...)`.
41 Any(Vec<Cfg>),
42 /// Intersection of a list of configuration requirements, i.e. `all(...)`.
43 All(Vec<Cfg>),
44 }
45
46 #[derive(PartialEq, Debug)]
47 pub struct InvalidCfgError {
48 pub msg: &'static str,
49 pub span: Span,
50 }
51
52 impl Cfg {
53 /// Parses a `NestedMetaItem` into a `Cfg`.
54 fn parse_nested(nested_cfg: &NestedMetaItem) -> Result<Cfg, InvalidCfgError> {
55 match nested_cfg.node {
56 NestedMetaItemKind::MetaItem(ref cfg) => Cfg::parse(cfg),
57 NestedMetaItemKind::Literal(ref lit) => Err(InvalidCfgError {
58 msg: "unexpected literal",
59 span: lit.span,
60 }),
61 }
62 }
63
64 /// Parses a `MetaItem` into a `Cfg`.
65 ///
66 /// The `MetaItem` should be the content of the `#[cfg(...)]`, e.g. `unix` or
67 /// `target_os = "redox"`.
68 ///
69 /// If the content is not properly formatted, it will return an error indicating what and where
70 /// the error is.
71 pub fn parse(cfg: &MetaItem) -> Result<Cfg, InvalidCfgError> {
72 let name = cfg.name();
73 match cfg.node {
74 MetaItemKind::Word => Ok(Cfg::Cfg(name, None)),
75 MetaItemKind::NameValue(ref lit) => match lit.node {
76 LitKind::Str(value, _) => Ok(Cfg::Cfg(name, Some(value))),
77 _ => Err(InvalidCfgError {
78 // FIXME: if the main #[cfg] syntax decided to support non-string literals,
79 // this should be changed as well.
80 msg: "value of cfg option should be a string literal",
81 span: lit.span,
82 }),
83 },
84 MetaItemKind::List(ref items) => {
85 let mut sub_cfgs = items.iter().map(Cfg::parse_nested);
86 match &*name.as_str() {
87 "all" => sub_cfgs.fold(Ok(Cfg::True), |x, y| Ok(x? & y?)),
88 "any" => sub_cfgs.fold(Ok(Cfg::False), |x, y| Ok(x? | y?)),
89 "not" => if sub_cfgs.len() == 1 {
90 Ok(!sub_cfgs.next().unwrap()?)
91 } else {
92 Err(InvalidCfgError {
93 msg: "expected 1 cfg-pattern",
94 span: cfg.span,
95 })
96 },
97 _ => Err(InvalidCfgError {
98 msg: "invalid predicate",
99 span: cfg.span,
100 }),
101 }
102 }
103 }
104 }
105
106 /// Checks whether the given configuration can be matched in the current session.
107 ///
108 /// Equivalent to `attr::cfg_matches`.
109 // FIXME: Actually make use of `features`.
110 pub fn matches(&self, parse_sess: &ParseSess, features: Option<&Features>) -> bool {
111 match *self {
112 Cfg::False => false,
113 Cfg::True => true,
114 Cfg::Not(ref child) => !child.matches(parse_sess, features),
115 Cfg::All(ref sub_cfgs) => {
116 sub_cfgs.iter().all(|sub_cfg| sub_cfg.matches(parse_sess, features))
117 },
118 Cfg::Any(ref sub_cfgs) => {
119 sub_cfgs.iter().any(|sub_cfg| sub_cfg.matches(parse_sess, features))
120 },
121 Cfg::Cfg(name, value) => parse_sess.config.contains(&(name, value)),
122 }
123 }
124
125 /// Whether the configuration consists of just `Cfg` or `Not`.
126 fn is_simple(&self) -> bool {
127 match *self {
128 Cfg::False | Cfg::True | Cfg::Cfg(..) | Cfg::Not(..) => true,
129 Cfg::All(..) | Cfg::Any(..) => false,
130 }
131 }
132
133 /// Whether the configuration consists of just `Cfg`, `Not` or `All`.
134 fn is_all(&self) -> bool {
135 match *self {
136 Cfg::False | Cfg::True | Cfg::Cfg(..) | Cfg::Not(..) | Cfg::All(..) => true,
137 Cfg::Any(..) => false,
138 }
139 }
140
141 /// Renders the configuration for human display, as a short HTML description.
142 pub(crate) fn render_short_html(&self) -> String {
143 let mut msg = Html(self).to_string();
144 if self.should_capitalize_first_letter() {
145 if let Some(i) = msg.find(|c: char| c.is_ascii_alphanumeric()) {
146 msg[i .. i+1].make_ascii_uppercase();
147 }
148 }
149 msg
150 }
151
152 /// Renders the configuration for long display, as a long HTML description.
153 pub(crate) fn render_long_html(&self) -> String {
154 let mut msg = format!("This is supported on <strong>{}</strong>", Html(self));
155 if self.should_append_only_to_description() {
156 msg.push_str(" only");
157 }
158 msg.push('.');
159 msg
160 }
161
162 fn should_capitalize_first_letter(&self) -> bool {
163 match *self {
164 Cfg::False | Cfg::True | Cfg::Not(..) => true,
165 Cfg::Any(ref sub_cfgs) | Cfg::All(ref sub_cfgs) => {
166 sub_cfgs.first().map(Cfg::should_capitalize_first_letter).unwrap_or(false)
167 },
168 Cfg::Cfg(name, _) => match &*name.as_str() {
169 "debug_assertions" | "target_endian" => true,
170 _ => false,
171 },
172 }
173 }
174
175 fn should_append_only_to_description(&self) -> bool {
176 match *self {
177 Cfg::False | Cfg::True => false,
178 Cfg::Any(..) | Cfg::All(..) | Cfg::Cfg(..) => true,
179 Cfg::Not(ref child) => match **child {
180 Cfg::Cfg(..) => true,
181 _ => false,
182 }
183 }
184 }
185 }
186
187 impl ops::Not for Cfg {
188 type Output = Cfg;
189 fn not(self) -> Cfg {
190 match self {
191 Cfg::False => Cfg::True,
192 Cfg::True => Cfg::False,
193 Cfg::Not(cfg) => *cfg,
194 s => Cfg::Not(Box::new(s)),
195 }
196 }
197 }
198
199 impl ops::BitAndAssign for Cfg {
200 fn bitand_assign(&mut self, other: Cfg) {
201 match (self, other) {
202 (&mut Cfg::False, _) | (_, Cfg::True) => {},
203 (s, Cfg::False) => *s = Cfg::False,
204 (s @ &mut Cfg::True, b) => *s = b,
205 (&mut Cfg::All(ref mut a), Cfg::All(ref mut b)) => a.append(b),
206 (&mut Cfg::All(ref mut a), ref mut b) => a.push(mem::replace(b, Cfg::True)),
207 (s, Cfg::All(mut a)) => {
208 let b = mem::replace(s, Cfg::True);
209 a.push(b);
210 *s = Cfg::All(a);
211 },
212 (s, b) => {
213 let a = mem::replace(s, Cfg::True);
214 *s = Cfg::All(vec![a, b]);
215 },
216 }
217 }
218 }
219
220 impl ops::BitAnd for Cfg {
221 type Output = Cfg;
222 fn bitand(mut self, other: Cfg) -> Cfg {
223 self &= other;
224 self
225 }
226 }
227
228 impl ops::BitOrAssign for Cfg {
229 fn bitor_assign(&mut self, other: Cfg) {
230 match (self, other) {
231 (&mut Cfg::True, _) | (_, Cfg::False) => {},
232 (s, Cfg::True) => *s = Cfg::True,
233 (s @ &mut Cfg::False, b) => *s = b,
234 (&mut Cfg::Any(ref mut a), Cfg::Any(ref mut b)) => a.append(b),
235 (&mut Cfg::Any(ref mut a), ref mut b) => a.push(mem::replace(b, Cfg::True)),
236 (s, Cfg::Any(mut a)) => {
237 let b = mem::replace(s, Cfg::True);
238 a.push(b);
239 *s = Cfg::Any(a);
240 },
241 (s, b) => {
242 let a = mem::replace(s, Cfg::True);
243 *s = Cfg::Any(vec![a, b]);
244 },
245 }
246 }
247 }
248
249 impl ops::BitOr for Cfg {
250 type Output = Cfg;
251 fn bitor(mut self, other: Cfg) -> Cfg {
252 self |= other;
253 self
254 }
255 }
256
257 struct Html<'a>(&'a Cfg);
258
259 fn write_with_opt_paren<T: fmt::Display>(
260 fmt: &mut fmt::Formatter,
261 has_paren: bool,
262 obj: T,
263 ) -> fmt::Result {
264 if has_paren {
265 fmt.write_char('(')?;
266 }
267 obj.fmt(fmt)?;
268 if has_paren {
269 fmt.write_char(')')?;
270 }
271 Ok(())
272 }
273
274
275 impl<'a> fmt::Display for Html<'a> {
276 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
277 match *self.0 {
278 Cfg::Not(ref child) => match **child {
279 Cfg::Any(ref sub_cfgs) => {
280 let separator = if sub_cfgs.iter().all(Cfg::is_simple) {
281 " nor "
282 } else {
283 ", nor "
284 };
285 for (i, sub_cfg) in sub_cfgs.iter().enumerate() {
286 fmt.write_str(if i == 0 { "neither " } else { separator })?;
287 write_with_opt_paren(fmt, !sub_cfg.is_all(), Html(sub_cfg))?;
288 }
289 Ok(())
290 }
291 ref simple @ Cfg::Cfg(..) => write!(fmt, "non-{}", Html(simple)),
292 ref c => write!(fmt, "not ({})", Html(c)),
293 },
294
295 Cfg::Any(ref sub_cfgs) => {
296 let separator = if sub_cfgs.iter().all(Cfg::is_simple) {
297 " or "
298 } else {
299 ", or "
300 };
301 for (i, sub_cfg) in sub_cfgs.iter().enumerate() {
302 if i != 0 {
303 fmt.write_str(separator)?;
304 }
305 write_with_opt_paren(fmt, !sub_cfg.is_all(), Html(sub_cfg))?;
306 }
307 Ok(())
308 },
309
310 Cfg::All(ref sub_cfgs) => {
311 for (i, sub_cfg) in sub_cfgs.iter().enumerate() {
312 if i != 0 {
313 fmt.write_str(" and ")?;
314 }
315 write_with_opt_paren(fmt, !sub_cfg.is_simple(), Html(sub_cfg))?;
316 }
317 Ok(())
318 },
319
320 Cfg::True => fmt.write_str("everywhere"),
321 Cfg::False => fmt.write_str("nowhere"),
322
323 Cfg::Cfg(name, value) => {
324 let n = &*name.as_str();
325 let human_readable = match (n, value) {
326 ("unix", None) => "Unix",
327 ("windows", None) => "Windows",
328 ("debug_assertions", None) => "debug-assertions enabled",
329 ("target_os", Some(os)) => match &*os.as_str() {
330 "android" => "Android",
331 "bitrig" => "Bitrig",
332 "dragonfly" => "DragonFly BSD",
333 "emscripten" => "Emscripten",
334 "freebsd" => "FreeBSD",
335 "fuchsia" => "Fuchsia",
336 "haiku" => "Haiku",
337 "ios" => "iOS",
338 "l4re" => "L4Re",
339 "linux" => "Linux",
340 "macos" => "macOS",
341 "netbsd" => "NetBSD",
342 "openbsd" => "OpenBSD",
343 "redox" => "Redox",
344 "solaris" => "Solaris",
345 "windows" => "Windows",
346 _ => "",
347 },
348 ("target_arch", Some(arch)) => match &*arch.as_str() {
349 "aarch64" => "AArch64",
350 "arm" => "ARM",
351 "asmjs" => "asm.js",
352 "mips" => "MIPS",
353 "mips64" => "MIPS-64",
354 "msp430" => "MSP430",
355 "powerpc" => "PowerPC",
356 "powerpc64" => "PowerPC-64",
357 "s390x" => "s390x",
358 "sparc64" => "SPARC64",
359 "wasm32" => "WebAssembly",
360 "x86" => "x86",
361 "x86_64" => "x86-64",
362 _ => "",
363 },
364 ("target_vendor", Some(vendor)) => match &*vendor.as_str() {
365 "apple" => "Apple",
366 "pc" => "PC",
367 "rumprun" => "Rumprun",
368 "sun" => "Sun",
369 _ => ""
370 },
371 ("target_env", Some(env)) => match &*env.as_str() {
372 "gnu" => "GNU",
373 "msvc" => "MSVC",
374 "musl" => "musl",
375 "newlib" => "Newlib",
376 "uclibc" => "uClibc",
377 _ => "",
378 },
379 ("target_endian", Some(endian)) => return write!(fmt, "{}-endian", endian),
380 ("target_pointer_width", Some(bits)) => return write!(fmt, "{}-bit", bits),
381 _ => "",
382 };
383 if !human_readable.is_empty() {
384 fmt.write_str(human_readable)
385 } else if let Some(v) = value {
386 write!(fmt, "<code>{}=\"{}\"</code>", Escape(n), Escape(&*v.as_str()))
387 } else {
388 write!(fmt, "<code>{}</code>", Escape(n))
389 }
390 }
391 }
392 }
393 }
394
395 #[cfg(test)]
396 mod test {
397 use super::Cfg;
398
399 use syntax::symbol::Symbol;
400 use syntax::ast::*;
401 use syntax::codemap::dummy_spanned;
402 use syntax_pos::DUMMY_SP;
403
404 fn word_cfg(s: &str) -> Cfg {
405 Cfg::Cfg(Symbol::intern(s), None)
406 }
407
408 fn name_value_cfg(name: &str, value: &str) -> Cfg {
409 Cfg::Cfg(Symbol::intern(name), Some(Symbol::intern(value)))
410 }
411
412 #[test]
413 fn test_cfg_not() {
414 assert_eq!(!Cfg::False, Cfg::True);
415 assert_eq!(!Cfg::True, Cfg::False);
416 assert_eq!(!word_cfg("test"), Cfg::Not(Box::new(word_cfg("test"))));
417 assert_eq!(
418 !Cfg::All(vec![word_cfg("a"), word_cfg("b")]),
419 Cfg::Not(Box::new(Cfg::All(vec![word_cfg("a"), word_cfg("b")])))
420 );
421 assert_eq!(
422 !Cfg::Any(vec![word_cfg("a"), word_cfg("b")]),
423 Cfg::Not(Box::new(Cfg::Any(vec![word_cfg("a"), word_cfg("b")])))
424 );
425 assert_eq!(!Cfg::Not(Box::new(word_cfg("test"))), word_cfg("test"));
426 }
427
428 #[test]
429 fn test_cfg_and() {
430 let mut x = Cfg::False;
431 x &= Cfg::True;
432 assert_eq!(x, Cfg::False);
433
434 x = word_cfg("test");
435 x &= Cfg::False;
436 assert_eq!(x, Cfg::False);
437
438 x = word_cfg("test2");
439 x &= Cfg::True;
440 assert_eq!(x, word_cfg("test2"));
441
442 x = Cfg::True;
443 x &= word_cfg("test3");
444 assert_eq!(x, word_cfg("test3"));
445
446 x &= word_cfg("test4");
447 assert_eq!(x, Cfg::All(vec![word_cfg("test3"), word_cfg("test4")]));
448
449 x &= word_cfg("test5");
450 assert_eq!(x, Cfg::All(vec![word_cfg("test3"), word_cfg("test4"), word_cfg("test5")]));
451
452 x &= Cfg::All(vec![word_cfg("test6"), word_cfg("test7")]);
453 assert_eq!(x, Cfg::All(vec![
454 word_cfg("test3"),
455 word_cfg("test4"),
456 word_cfg("test5"),
457 word_cfg("test6"),
458 word_cfg("test7"),
459 ]));
460
461 let mut y = Cfg::Any(vec![word_cfg("a"), word_cfg("b")]);
462 y &= x;
463 assert_eq!(y, Cfg::All(vec![
464 word_cfg("test3"),
465 word_cfg("test4"),
466 word_cfg("test5"),
467 word_cfg("test6"),
468 word_cfg("test7"),
469 Cfg::Any(vec![word_cfg("a"), word_cfg("b")]),
470 ]));
471
472 assert_eq!(
473 word_cfg("a") & word_cfg("b") & word_cfg("c"),
474 Cfg::All(vec![word_cfg("a"), word_cfg("b"), word_cfg("c")])
475 );
476 }
477
478 #[test]
479 fn test_cfg_or() {
480 let mut x = Cfg::True;
481 x |= Cfg::False;
482 assert_eq!(x, Cfg::True);
483
484 x = word_cfg("test");
485 x |= Cfg::True;
486 assert_eq!(x, Cfg::True);
487
488 x = word_cfg("test2");
489 x |= Cfg::False;
490 assert_eq!(x, word_cfg("test2"));
491
492 x = Cfg::False;
493 x |= word_cfg("test3");
494 assert_eq!(x, word_cfg("test3"));
495
496 x |= word_cfg("test4");
497 assert_eq!(x, Cfg::Any(vec![word_cfg("test3"), word_cfg("test4")]));
498
499 x |= word_cfg("test5");
500 assert_eq!(x, Cfg::Any(vec![word_cfg("test3"), word_cfg("test4"), word_cfg("test5")]));
501
502 x |= Cfg::Any(vec![word_cfg("test6"), word_cfg("test7")]);
503 assert_eq!(x, Cfg::Any(vec![
504 word_cfg("test3"),
505 word_cfg("test4"),
506 word_cfg("test5"),
507 word_cfg("test6"),
508 word_cfg("test7"),
509 ]));
510
511 let mut y = Cfg::All(vec![word_cfg("a"), word_cfg("b")]);
512 y |= x;
513 assert_eq!(y, Cfg::Any(vec![
514 word_cfg("test3"),
515 word_cfg("test4"),
516 word_cfg("test5"),
517 word_cfg("test6"),
518 word_cfg("test7"),
519 Cfg::All(vec![word_cfg("a"), word_cfg("b")]),
520 ]));
521
522 assert_eq!(
523 word_cfg("a") | word_cfg("b") | word_cfg("c"),
524 Cfg::Any(vec![word_cfg("a"), word_cfg("b"), word_cfg("c")])
525 );
526 }
527
528 #[test]
529 fn test_parse_ok() {
530 let mi = MetaItem {
531 name: Symbol::intern("all"),
532 node: MetaItemKind::Word,
533 span: DUMMY_SP,
534 };
535 assert_eq!(Cfg::parse(&mi), Ok(word_cfg("all")));
536
537 let mi = MetaItem {
538 name: Symbol::intern("all"),
539 node: MetaItemKind::NameValue(dummy_spanned(LitKind::Str(
540 Symbol::intern("done"),
541 StrStyle::Cooked,
542 ))),
543 span: DUMMY_SP,
544 };
545 assert_eq!(Cfg::parse(&mi), Ok(name_value_cfg("all", "done")));
546
547 let mi = MetaItem {
548 name: Symbol::intern("all"),
549 node: MetaItemKind::List(vec![
550 dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem {
551 name: Symbol::intern("a"),
552 node: MetaItemKind::Word,
553 span: DUMMY_SP,
554 })),
555 dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem {
556 name: Symbol::intern("b"),
557 node: MetaItemKind::Word,
558 span: DUMMY_SP,
559 })),
560 ]),
561 span: DUMMY_SP,
562 };
563 assert_eq!(Cfg::parse(&mi), Ok(word_cfg("a") & word_cfg("b")));
564
565 let mi = MetaItem {
566 name: Symbol::intern("any"),
567 node: MetaItemKind::List(vec![
568 dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem {
569 name: Symbol::intern("a"),
570 node: MetaItemKind::Word,
571 span: DUMMY_SP,
572 })),
573 dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem {
574 name: Symbol::intern("b"),
575 node: MetaItemKind::Word,
576 span: DUMMY_SP,
577 })),
578 ]),
579 span: DUMMY_SP,
580 };
581 assert_eq!(Cfg::parse(&mi), Ok(word_cfg("a") | word_cfg("b")));
582
583 let mi = MetaItem {
584 name: Symbol::intern("not"),
585 node: MetaItemKind::List(vec![
586 dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem {
587 name: Symbol::intern("a"),
588 node: MetaItemKind::Word,
589 span: DUMMY_SP,
590 })),
591 ]),
592 span: DUMMY_SP,
593 };
594 assert_eq!(Cfg::parse(&mi), Ok(!word_cfg("a")));
595
596 let mi = MetaItem {
597 name: Symbol::intern("not"),
598 node: MetaItemKind::List(vec![
599 dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem {
600 name: Symbol::intern("any"),
601 node: MetaItemKind::List(vec![
602 dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem {
603 name: Symbol::intern("a"),
604 node: MetaItemKind::Word,
605 span: DUMMY_SP,
606 })),
607 dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem {
608 name: Symbol::intern("all"),
609 node: MetaItemKind::List(vec![
610 dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem {
611 name: Symbol::intern("b"),
612 node: MetaItemKind::Word,
613 span: DUMMY_SP,
614 })),
615 dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem {
616 name: Symbol::intern("c"),
617 node: MetaItemKind::Word,
618 span: DUMMY_SP,
619 })),
620 ]),
621 span: DUMMY_SP,
622 })),
623 ]),
624 span: DUMMY_SP,
625 })),
626 ]),
627 span: DUMMY_SP,
628 };
629 assert_eq!(Cfg::parse(&mi), Ok(!(word_cfg("a") | (word_cfg("b") & word_cfg("c")))));
630
631 let mi = MetaItem {
632 name: Symbol::intern("all"),
633 node: MetaItemKind::List(vec![
634 dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem {
635 name: Symbol::intern("a"),
636 node: MetaItemKind::Word,
637 span: DUMMY_SP,
638 })),
639 dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem {
640 name: Symbol::intern("b"),
641 node: MetaItemKind::Word,
642 span: DUMMY_SP,
643 })),
644 dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem {
645 name: Symbol::intern("c"),
646 node: MetaItemKind::Word,
647 span: DUMMY_SP,
648 })),
649 ]),
650 span: DUMMY_SP,
651 };
652 assert_eq!(Cfg::parse(&mi), Ok(word_cfg("a") & word_cfg("b") & word_cfg("c")));
653 }
654
655 #[test]
656 fn test_parse_err() {
657 let mi = MetaItem {
658 name: Symbol::intern("foo"),
659 node: MetaItemKind::NameValue(dummy_spanned(LitKind::Bool(false))),
660 span: DUMMY_SP,
661 };
662 assert!(Cfg::parse(&mi).is_err());
663
664 let mi = MetaItem {
665 name: Symbol::intern("not"),
666 node: MetaItemKind::List(vec![
667 dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem {
668 name: Symbol::intern("a"),
669 node: MetaItemKind::Word,
670 span: DUMMY_SP,
671 })),
672 dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem {
673 name: Symbol::intern("b"),
674 node: MetaItemKind::Word,
675 span: DUMMY_SP,
676 })),
677 ]),
678 span: DUMMY_SP,
679 };
680 assert!(Cfg::parse(&mi).is_err());
681
682 let mi = MetaItem {
683 name: Symbol::intern("not"),
684 node: MetaItemKind::List(vec![]),
685 span: DUMMY_SP,
686 };
687 assert!(Cfg::parse(&mi).is_err());
688
689 let mi = MetaItem {
690 name: Symbol::intern("foo"),
691 node: MetaItemKind::List(vec![
692 dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem {
693 name: Symbol::intern("a"),
694 node: MetaItemKind::Word,
695 span: DUMMY_SP,
696 })),
697 ]),
698 span: DUMMY_SP,
699 };
700 assert!(Cfg::parse(&mi).is_err());
701
702 let mi = MetaItem {
703 name: Symbol::intern("all"),
704 node: MetaItemKind::List(vec![
705 dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem {
706 name: Symbol::intern("foo"),
707 node: MetaItemKind::List(vec![]),
708 span: DUMMY_SP,
709 })),
710 dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem {
711 name: Symbol::intern("b"),
712 node: MetaItemKind::Word,
713 span: DUMMY_SP,
714 })),
715 ]),
716 span: DUMMY_SP,
717 };
718 assert!(Cfg::parse(&mi).is_err());
719
720 let mi = MetaItem {
721 name: Symbol::intern("any"),
722 node: MetaItemKind::List(vec![
723 dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem {
724 name: Symbol::intern("a"),
725 node: MetaItemKind::Word,
726 span: DUMMY_SP,
727 })),
728 dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem {
729 name: Symbol::intern("foo"),
730 node: MetaItemKind::List(vec![]),
731 span: DUMMY_SP,
732 })),
733 ]),
734 span: DUMMY_SP,
735 };
736 assert!(Cfg::parse(&mi).is_err());
737
738 let mi = MetaItem {
739 name: Symbol::intern("not"),
740 node: MetaItemKind::List(vec![
741 dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem {
742 name: Symbol::intern("foo"),
743 node: MetaItemKind::List(vec![]),
744 span: DUMMY_SP,
745 })),
746 ]),
747 span: DUMMY_SP,
748 };
749 assert!(Cfg::parse(&mi).is_err());
750 }
751
752 #[test]
753 fn test_render_short_html() {
754 assert_eq!(
755 word_cfg("unix").render_short_html(),
756 "Unix"
757 );
758 assert_eq!(
759 name_value_cfg("target_os", "macos").render_short_html(),
760 "macOS"
761 );
762 assert_eq!(
763 name_value_cfg("target_pointer_width", "16").render_short_html(),
764 "16-bit"
765 );
766 assert_eq!(
767 name_value_cfg("target_endian", "little").render_short_html(),
768 "Little-endian"
769 );
770 assert_eq!(
771 (!word_cfg("windows")).render_short_html(),
772 "Non-Windows"
773 );
774 assert_eq!(
775 (word_cfg("unix") & word_cfg("windows")).render_short_html(),
776 "Unix and Windows"
777 );
778 assert_eq!(
779 (word_cfg("unix") | word_cfg("windows")).render_short_html(),
780 "Unix or Windows"
781 );
782 assert_eq!(
783 (
784 word_cfg("unix") & word_cfg("windows") & word_cfg("debug_assertions")
785 ).render_short_html(),
786 "Unix and Windows and debug-assertions enabled"
787 );
788 assert_eq!(
789 (
790 word_cfg("unix") | word_cfg("windows") | word_cfg("debug_assertions")
791 ).render_short_html(),
792 "Unix or Windows or debug-assertions enabled"
793 );
794 assert_eq!(
795 (
796 !(word_cfg("unix") | word_cfg("windows") | word_cfg("debug_assertions"))
797 ).render_short_html(),
798 "Neither Unix nor Windows nor debug-assertions enabled"
799 );
800 assert_eq!(
801 (
802 (word_cfg("unix") & name_value_cfg("target_arch", "x86_64")) |
803 (word_cfg("windows") & name_value_cfg("target_pointer_width", "64"))
804 ).render_short_html(),
805 "Unix and x86-64, or Windows and 64-bit"
806 );
807 assert_eq!(
808 (!(word_cfg("unix") & word_cfg("windows"))).render_short_html(),
809 "Not (Unix and Windows)"
810 );
811 assert_eq!(
812 (
813 (word_cfg("debug_assertions") | word_cfg("windows")) & word_cfg("unix")
814 ).render_short_html(),
815 "(Debug-assertions enabled or Windows) and Unix"
816 );
817 }
818
819 #[test]
820 fn test_render_long_html() {
821 assert_eq!(
822 word_cfg("unix").render_long_html(),
823 "This is supported on <strong>Unix</strong> only."
824 );
825 assert_eq!(
826 name_value_cfg("target_os", "macos").render_long_html(),
827 "This is supported on <strong>macOS</strong> only."
828 );
829 assert_eq!(
830 name_value_cfg("target_pointer_width", "16").render_long_html(),
831 "This is supported on <strong>16-bit</strong> only."
832 );
833 assert_eq!(
834 name_value_cfg("target_endian", "little").render_long_html(),
835 "This is supported on <strong>little-endian</strong> only."
836 );
837 assert_eq!(
838 (!word_cfg("windows")).render_long_html(),
839 "This is supported on <strong>non-Windows</strong> only."
840 );
841 assert_eq!(
842 (word_cfg("unix") & word_cfg("windows")).render_long_html(),
843 "This is supported on <strong>Unix and Windows</strong> only."
844 );
845 assert_eq!(
846 (word_cfg("unix") | word_cfg("windows")).render_long_html(),
847 "This is supported on <strong>Unix or Windows</strong> only."
848 );
849 assert_eq!(
850 (
851 word_cfg("unix") & word_cfg("windows") & word_cfg("debug_assertions")
852 ).render_long_html(),
853 "This is supported on <strong>Unix and Windows and debug-assertions enabled</strong> \
854 only."
855 );
856 assert_eq!(
857 (
858 word_cfg("unix") | word_cfg("windows") | word_cfg("debug_assertions")
859 ).render_long_html(),
860 "This is supported on <strong>Unix or Windows or debug-assertions enabled</strong> \
861 only."
862 );
863 assert_eq!(
864 (
865 !(word_cfg("unix") | word_cfg("windows") | word_cfg("debug_assertions"))
866 ).render_long_html(),
867 "This is supported on <strong>neither Unix nor Windows nor debug-assertions \
868 enabled</strong>."
869 );
870 assert_eq!(
871 (
872 (word_cfg("unix") & name_value_cfg("target_arch", "x86_64")) |
873 (word_cfg("windows") & name_value_cfg("target_pointer_width", "64"))
874 ).render_long_html(),
875 "This is supported on <strong>Unix and x86-64, or Windows and 64-bit</strong> only."
876 );
877 assert_eq!(
878 (!(word_cfg("unix") & word_cfg("windows"))).render_long_html(),
879 "This is supported on <strong>not (Unix and Windows)</strong>."
880 );
881 assert_eq!(
882 (
883 (word_cfg("debug_assertions") | word_cfg("windows")) & word_cfg("unix")
884 ).render_long_html(),
885 "This is supported on <strong>(debug-assertions enabled or Windows) and Unix</strong> \
886 only."
887 );
888 }
889 }