@@ -547,8 +547,97 @@ static bool isVersionIfConfigCondition(Expr *Condition) {
547
547
return IsVersionIfConfigCondition ().visit (Condition);
548
548
}
549
549
550
+ // / Get the identifier string from an \c Expr if it's an
551
+ // / \c UnresolvedDeclRefExpr, otherwise the empty string.
552
+ static StringRef getDeclRefStr (Expr *E) {
553
+ if (auto *UDRE = cast<UnresolvedDeclRefExpr>(E)) {
554
+ return UDRE->getName ().getBaseIdentifier ().str ();
555
+ }
556
+ return " " ;
557
+ }
558
+
559
+ static bool isPlatformConditionDisjunction (Expr *E, PlatformConditionKind Kind,
560
+ ArrayRef<StringRef> Vals) {
561
+ if (auto *Or = dyn_cast<BinaryExpr>(E)) {
562
+ if (getDeclRefStr (Or->getFn ()) == " ||" ) {
563
+ auto Args = Or->getArg ()->getElements ();
564
+ return (isPlatformConditionDisjunction (Args[0 ], Kind, Vals) &&
565
+ isPlatformConditionDisjunction (Args[1 ], Kind, Vals));
566
+ }
567
+ } else if (auto *P = dyn_cast<ParenExpr>(E)) {
568
+ return isPlatformConditionDisjunction (P->getSubExpr (), Kind, Vals);
569
+ } else if (auto *C = dyn_cast<CallExpr>(E)) {
570
+ if (getPlatformConditionKind (getDeclRefStr (C->getFn ())) != Kind)
571
+ return false ;
572
+ if (auto *ArgP = dyn_cast<ParenExpr>(C->getArg ())) {
573
+ if (auto *Arg = ArgP->getSubExpr ()) {
574
+ auto ArgStr = getDeclRefStr (Arg);
575
+ for (auto V : Vals) {
576
+ if (ArgStr == V)
577
+ return true ;
578
+ }
579
+ }
580
+ }
581
+ }
582
+ return false ;
583
+ }
584
+
585
+ // Search for the first occurrence of a _likely_ (but not definite) implicit
586
+ // simulator-environment platform condition, or negation thereof. This is
587
+ // defined as any logical conjunction of one or more os() platform conditions
588
+ // _strictly_ from the set {iOS, tvOS, watchOS} and one or more arch() platform
589
+ // conditions _strictly_ from the set {i386, x86_64}.
590
+ //
591
+ // These are (at the time of writing) defined as de-facto simulators in
592
+ // Platform.cpp, and if a user is testing them they're _likely_ looking for
593
+ // simulator-ness indirectly. If there is anything else in the condition aside
594
+ // from these conditions (or the negation of such a conjunction), we
595
+ // conservatively assume the user is testing something other than
596
+ // simulator-ness.
597
+ static Expr *findAnyLikelySimulatorEnvironmentTest (Expr *Condition) {
598
+
599
+ if (!Condition)
600
+ return nullptr ;
601
+
602
+ if (auto *N = dyn_cast<PrefixUnaryExpr>(Condition)) {
603
+ return findAnyLikelySimulatorEnvironmentTest (N->getArg ());
604
+ } else if (auto *P = dyn_cast<ParenExpr>(Condition)) {
605
+ return findAnyLikelySimulatorEnvironmentTest (P->getSubExpr ());
606
+ }
607
+
608
+ // We assume the user is writing the condition in CNF -- say (os(iOS) ||
609
+ // os(tvOS)) && (arch(i386) || arch(x86_64)) -- rather than DNF, as the former
610
+ // is exponentially more terse, and these conditions are already quite
611
+ // unwieldy. If field evidence shows people using other variants, possibly add
612
+ // them here.
613
+
614
+ auto isSimulatorPlatformOSTest = [](Expr *E) -> bool {
615
+ return isPlatformConditionDisjunction (
616
+ E, PlatformConditionKind::OS, {" iOS" , " tvOS" , " watchOS" });
617
+ };
618
+
619
+ auto isSimulatorPlatformArchTest = [](Expr *E) -> bool {
620
+ return isPlatformConditionDisjunction (
621
+ E, PlatformConditionKind::Arch, {" i386" , " x86_64" });
622
+ };
623
+
624
+ if (auto *And = dyn_cast<BinaryExpr>(Condition)) {
625
+ if (getDeclRefStr (And->getFn ()) == " &&" ) {
626
+ auto Args = And->getArg ()->getElements ();
627
+ if ((isSimulatorPlatformOSTest (Args[0 ]) &&
628
+ isSimulatorPlatformArchTest (Args[1 ])) ||
629
+ (isSimulatorPlatformOSTest (Args[1 ]) &&
630
+ isSimulatorPlatformArchTest (Args[0 ]))) {
631
+ return And;
632
+ }
633
+ }
634
+ }
635
+ return nullptr ;
636
+ }
637
+
550
638
} // end anonymous namespace
551
639
640
+
552
641
// / Parse and populate a #if ... #endif directive.
553
642
// / Delegate callback function to parse elements in the blocks.
554
643
ParserResult<IfConfigDecl> Parser::parseIfConfig (
@@ -597,6 +686,13 @@ ParserResult<IfConfigDecl> Parser::parseIfConfig(
597
686
diag::extra_tokens_conditional_compilation_directive);
598
687
}
599
688
689
+ if (Expr *Test = findAnyLikelySimulatorEnvironmentTest (Condition)) {
690
+ diagnose (Test->getLoc (),
691
+ diag::likely_simulator_platform_condition)
692
+ .fixItReplace (Test->getSourceRange (),
693
+ " targetEnvironment(simulator)" );
694
+ }
695
+
600
696
// Parse elements
601
697
SmallVector<ASTNode, 16 > Elements;
602
698
if (isActive || !isVersionCondition) {
0 commit comments