Properly escape define values with spaces

Previously they were not handled properly, leading to indexing
errors.

PiperOrigin-RevId: 251724057
diff --git a/src/TulsiGenerator/PBXTargetGenerator.swift b/src/TulsiGenerator/PBXTargetGenerator.swift
index c27b703..d99ebf5 100644
--- a/src/TulsiGenerator/PBXTargetGenerator.swift
+++ b/src/TulsiGenerator/PBXTargetGenerator.swift
@@ -1041,8 +1041,8 @@
   }
 
   // Adds XCBuildConfigurations to the given indexer PBXTarget.
-  // Note that preprocessorDefines is expected to be a pre-quoted set of defines (e.g., if "key" has
-  // spaces it would be the string: key="value with spaces").
+  // Note that preprocessorDefines may or may not contain values with spaces. If it does contain
+  // spaces, the key will be escaped (e.g. -Dfoo bar becomes -D"foo bar").
   private func addConfigsForIndexingTarget(_ target: PBXTarget, data: IndexerData) {
 
     var buildSettings = options.buildSettingsForTarget(target.name)
@@ -1053,8 +1053,17 @@
     }
 
     var allOtherCFlags = data.otherCFlags.filter { !$0.hasPrefix("-W") }
+    // Escape the spaces in the defines by transforming -Dfoo bar into -D"foo bar".
     if !data.preprocessorDefines.isEmpty {
-      allOtherCFlags.append(contentsOf: data.preprocessorDefines.sorted().map({"-D\($0)"}))
+      allOtherCFlags.append(contentsOf: data.preprocessorDefines.sorted().map { define in
+        // Need to quote all defines with spaces that are not yet quoted.
+        if define.rangeOfCharacter(from: .whitespaces) != nil &&
+            !((define.hasPrefix("\"") && define.hasSuffix("\"")) ||
+              (define.hasPrefix("'") && define.hasSuffix("'"))) {
+          return "-D\"\(define)\""
+        }
+        return "-D\(define)"
+      })
     }
 
     if !allOtherCFlags.isEmpty {
diff --git a/src/TulsiGeneratorIntegrationTests/AspectTests.swift b/src/TulsiGeneratorIntegrationTests/AspectTests.swift
index 735dfc3..abd6842 100644
--- a/src/TulsiGeneratorIntegrationTests/AspectTests.swift
+++ b/src/TulsiGeneratorIntegrationTests/AspectTests.swift
@@ -278,9 +278,9 @@
         .hasAttribute(.copts, value: ["-DSubLibraryWithDifferentDefines_LocalDefine",
                                       "-DSubLibraryWithDifferentDefines_INTEGER_DEFINE=1",
                                       "-DSubLibraryWithDifferentDefines_STRING_DEFINE=Test",
-                                      "-DSubLibraryWithDifferentDefines_STRING_WITH_SPACES='String with spaces'",
-                                      "-D'SubLibraryWithDifferentDefines Define with spaces'",
-                                      "-D'SubLibraryWithDifferentDefines Define with spaces and value'=1"] as NSArray)
+                                      "-DSubLibraryWithDifferentDefines_STRING_WITH_SPACES=String with spaces",
+                                      "-D'SubLibraryWithDifferentDefines_SINGLEQUOTED=Single quoted with spaces'",
+                                      "-D\"SubLibraryWithDifferentDefines_PREQUOTED=Prequoted with spaces\""] as NSArray)
         .hasObjcDefines(["SubLibraryWithDifferentDefines=1"])
         .hasIncludes(["tulsi_test/SubLibraryWithDifferentDefines/includes",
                       "tulsi-includes/x/x/tulsi_test/SubLibraryWithDifferentDefines/includes"])
diff --git a/src/TulsiGeneratorIntegrationTests/Resources/ComplexSingle.BUILD b/src/TulsiGeneratorIntegrationTests/Resources/ComplexSingle.BUILD
index addad25..45fbfce 100644
--- a/src/TulsiGeneratorIntegrationTests/Resources/ComplexSingle.BUILD
+++ b/src/TulsiGeneratorIntegrationTests/Resources/ComplexSingle.BUILD
@@ -198,9 +198,9 @@
         "-DSubLibraryWithDifferentDefines_LocalDefine",
         "-DSubLibraryWithDifferentDefines_INTEGER_DEFINE=1",
         "-DSubLibraryWithDifferentDefines_STRING_DEFINE=Test",
-        "-DSubLibraryWithDifferentDefines_STRING_WITH_SPACES='String with spaces'",
-        "-D'SubLibraryWithDifferentDefines Define with spaces'",
-        "-D'SubLibraryWithDifferentDefines Define with spaces and value'=1",
+        "-DSubLibraryWithDifferentDefines_STRING_WITH_SPACES=String with spaces",
+        "-D'SubLibraryWithDifferentDefines_SINGLEQUOTED=Single quoted with spaces'",
+        "-D\"SubLibraryWithDifferentDefines_PREQUOTED=Prequoted with spaces\"",
     ],
     defines = [
         "SubLibraryWithDifferentDefines=1",
diff --git a/src/TulsiGeneratorIntegrationTests/Resources/GoldenProjects/ComplexSingleProject.xcodeproj/project.pbxproj b/src/TulsiGeneratorIntegrationTests/Resources/GoldenProjects/ComplexSingleProject.xcodeproj/project.pbxproj
index 48f0ea7..aa434ec 100644
--- a/src/TulsiGeneratorIntegrationTests/Resources/GoldenProjects/ComplexSingleProject.xcodeproj/project.pbxproj
+++ b/src/TulsiGeneratorIntegrationTests/Resources/GoldenProjects/ComplexSingleProject.xcodeproj/project.pbxproj
@@ -1125,7 +1125,7 @@
 				GCC_PREPROCESSOR_DEFINITIONS = "DEBUG=1";
 				HEADER_SEARCH_PATHS = "$(inherited) $(TULSI_WR)/tulsi_e2e_complex/Application/includes/first/include $(TULSI_WR)/_tulsi-includes/x/x/tulsi_e2e_complex/Application/includes/first/include $(TULSI_WR)/tulsi_e2e_complex/Application/includes/second/include $(TULSI_WR)/_tulsi-includes/x/x/tulsi_e2e_complex/Application/includes/second/include $(TULSI_WR)/tulsi_e2e_complex/SubLibraryWithDifferentDefines/includes $(TULSI_WR)/_tulsi-includes/x/x/tulsi_e2e_complex/SubLibraryWithDifferentDefines/includes $(TULSI_WR)/_tulsi-includes/x/x/ $(TULSI_BWRS)/tulsi_e2e_complex/Application/includes/first/include $(TULSI_BWRS)/_tulsi-includes/x/x/tulsi_e2e_complex/Application/includes/first/include $(TULSI_BWRS)/tulsi_e2e_complex/Application/includes/second/include $(TULSI_BWRS)/_tulsi-includes/x/x/tulsi_e2e_complex/Application/includes/second/include $(TULSI_BWRS)/tulsi_e2e_complex/SubLibraryWithDifferentDefines/includes $(TULSI_BWRS)/_tulsi-includes/x/x/tulsi_e2e_complex/SubLibraryWithDifferentDefines/includes $(TULSI_BWRS)/_tulsi-includes/x/x/ ";
 				IPHONEOS_DEPLOYMENT_TARGET = 10.0;
-				OTHER_CFLAGS = "-DA=BINARY_DEFINE -DLIBRARY SECOND DEFINE=2 -DLIBRARY_DEFINES_DEFINE=1 -DLIBRARY_VALUE_WITH_SPACES=Value with spaces -DSubLibraryWithDefines=1 -DSubLibraryWithDefines_DEFINE=SubLibraryWithDefines -DSubLibraryWithDifferentDefines=1";
+				OTHER_CFLAGS = "-DA=BINARY_DEFINE -D\"LIBRARY SECOND DEFINE=2\" -DLIBRARY_DEFINES_DEFINE=1 -D\"LIBRARY_VALUE_WITH_SPACES=Value with spaces\" -DSubLibraryWithDefines=1 -DSubLibraryWithDefines_DEFINE=SubLibraryWithDefines -DSubLibraryWithDifferentDefines=1";
 				PRODUCT_NAME = _idx_ApplicationLibrary_3EA018EE_ios_min10.0;
 				SDKROOT = iphoneos;
 				USER_HEADER_SEARCH_PATHS = "$(TULSI_WR)";
@@ -1150,7 +1150,7 @@
 				GCC_PREPROCESSOR_DEFINITIONS = "DEBUG=1";
 				HEADER_SEARCH_PATHS = "$(inherited) $(TULSI_WR)/tulsi_e2e_complex/SubLibraryWithDifferentDefines/includes $(TULSI_WR)/_tulsi-includes/x/x/tulsi_e2e_complex/SubLibraryWithDifferentDefines/includes $(TULSI_WR)/_tulsi-includes/x/x/ $(TULSI_BWRS)/tulsi_e2e_complex/SubLibraryWithDifferentDefines/includes $(TULSI_BWRS)/_tulsi-includes/x/x/tulsi_e2e_complex/SubLibraryWithDifferentDefines/includes $(TULSI_BWRS)/_tulsi-includes/x/x/ ";
 				IPHONEOS_DEPLOYMENT_TARGET = 10.0;
-				OTHER_CFLAGS = "-DLIBRARY SECOND DEFINE=2 -DLIBRARY_COPT_DEFINE -DLIBRARY_DEFINES_DEFINE=1 -DLIBRARY_VALUE_WITH_SPACES=Value with spaces -DSubLibraryWithDefines=1 -DSubLibraryWithDefines_DEFINE=SubLibraryWithDefines -DSubLibraryWithDifferentDefines=1";
+				OTHER_CFLAGS = "-D\"LIBRARY SECOND DEFINE=2\" -DLIBRARY_COPT_DEFINE -DLIBRARY_DEFINES_DEFINE=1 -D\"LIBRARY_VALUE_WITH_SPACES=Value with spaces\" -DSubLibraryWithDefines=1 -DSubLibraryWithDefines_DEFINE=SubLibraryWithDefines -DSubLibraryWithDifferentDefines=1";
 				PRODUCT_NAME = _idx_Library_FAFE9183_ios_min10.0;
 				SDKROOT = iphoneos;
 				USER_HEADER_SEARCH_PATHS = "$(TULSI_WR)";
@@ -1190,7 +1190,7 @@
 				GCC_PREPROCESSOR_DEFINITIONS = "DEBUG=1";
 				HEADER_SEARCH_PATHS = "$(inherited) $(TULSI_WR)/tulsi_e2e_complex/SubLibraryWithDifferentDefines/includes $(TULSI_WR)/_tulsi-includes/x/x/tulsi_e2e_complex/SubLibraryWithDifferentDefines/includes $(TULSI_WR)/_tulsi-includes/x/x/ $(TULSI_BWRS)/tulsi_e2e_complex/SubLibraryWithDifferentDefines/includes $(TULSI_BWRS)/_tulsi-includes/x/x/tulsi_e2e_complex/SubLibraryWithDifferentDefines/includes $(TULSI_BWRS)/_tulsi-includes/x/x/ ";
 				IPHONEOS_DEPLOYMENT_TARGET = 10.0;
-				OTHER_CFLAGS = "-D'SubLibraryWithDifferentDefines Define with spaces and value'=1 -D'SubLibraryWithDifferentDefines Define with spaces' -DSubLibraryWithDifferentDefines=1 -DSubLibraryWithDifferentDefines_INTEGER_DEFINE=1 -DSubLibraryWithDifferentDefines_LocalDefine -DSubLibraryWithDifferentDefines_STRING_DEFINE=Test -DSubLibraryWithDifferentDefines_STRING_WITH_SPACES='String with spaces'";
+				OTHER_CFLAGS = "-D\"SubLibraryWithDifferentDefines_PREQUOTED=Prequoted with spaces\" -D'SubLibraryWithDifferentDefines_SINGLEQUOTED=Single quoted with spaces' -DSubLibraryWithDifferentDefines=1 -DSubLibraryWithDifferentDefines_INTEGER_DEFINE=1 -DSubLibraryWithDifferentDefines_LocalDefine -DSubLibraryWithDifferentDefines_STRING_DEFINE=Test -D\"SubLibraryWithDifferentDefines_STRING_WITH_SPACES=String with spaces\"";
 				PRODUCT_NAME = _idx_SubLibraryWithDifferentDefines_B982A5CC_ios_min10.0;
 				SDKROOT = iphoneos;
 				USER_HEADER_SEARCH_PATHS = "$(TULSI_WR)";
@@ -1307,7 +1307,7 @@
 				GCC_PREPROCESSOR_DEFINITIONS = "NDEBUG=1";
 				HEADER_SEARCH_PATHS = "$(inherited) $(TULSI_WR)/tulsi_e2e_complex/Application/includes/first/include $(TULSI_WR)/_tulsi-includes/x/x/tulsi_e2e_complex/Application/includes/first/include $(TULSI_WR)/tulsi_e2e_complex/Application/includes/second/include $(TULSI_WR)/_tulsi-includes/x/x/tulsi_e2e_complex/Application/includes/second/include $(TULSI_WR)/tulsi_e2e_complex/SubLibraryWithDifferentDefines/includes $(TULSI_WR)/_tulsi-includes/x/x/tulsi_e2e_complex/SubLibraryWithDifferentDefines/includes $(TULSI_WR)/_tulsi-includes/x/x/ $(TULSI_BWRS)/tulsi_e2e_complex/Application/includes/first/include $(TULSI_BWRS)/_tulsi-includes/x/x/tulsi_e2e_complex/Application/includes/first/include $(TULSI_BWRS)/tulsi_e2e_complex/Application/includes/second/include $(TULSI_BWRS)/_tulsi-includes/x/x/tulsi_e2e_complex/Application/includes/second/include $(TULSI_BWRS)/tulsi_e2e_complex/SubLibraryWithDifferentDefines/includes $(TULSI_BWRS)/_tulsi-includes/x/x/tulsi_e2e_complex/SubLibraryWithDifferentDefines/includes $(TULSI_BWRS)/_tulsi-includes/x/x/ ";
 				IPHONEOS_DEPLOYMENT_TARGET = 10.0;
-				OTHER_CFLAGS = "-DA=BINARY_DEFINE -DLIBRARY SECOND DEFINE=2 -DLIBRARY_DEFINES_DEFINE=1 -DLIBRARY_VALUE_WITH_SPACES=Value with spaces -DSubLibraryWithDefines=1 -DSubLibraryWithDefines_DEFINE=SubLibraryWithDefines -DSubLibraryWithDifferentDefines=1";
+				OTHER_CFLAGS = "-DA=BINARY_DEFINE -D\"LIBRARY SECOND DEFINE=2\" -DLIBRARY_DEFINES_DEFINE=1 -D\"LIBRARY_VALUE_WITH_SPACES=Value with spaces\" -DSubLibraryWithDefines=1 -DSubLibraryWithDefines_DEFINE=SubLibraryWithDefines -DSubLibraryWithDifferentDefines=1";
 				PRODUCT_NAME = _idx_ApplicationLibrary_3EA018EE_ios_min10.0;
 				SDKROOT = iphoneos;
 				USER_HEADER_SEARCH_PATHS = "$(TULSI_WR)";
@@ -1332,7 +1332,7 @@
 				GCC_PREPROCESSOR_DEFINITIONS = "NDEBUG=1";
 				HEADER_SEARCH_PATHS = "$(inherited) $(TULSI_WR)/tulsi_e2e_complex/SubLibraryWithDifferentDefines/includes $(TULSI_WR)/_tulsi-includes/x/x/tulsi_e2e_complex/SubLibraryWithDifferentDefines/includes $(TULSI_WR)/_tulsi-includes/x/x/ $(TULSI_BWRS)/tulsi_e2e_complex/SubLibraryWithDifferentDefines/includes $(TULSI_BWRS)/_tulsi-includes/x/x/tulsi_e2e_complex/SubLibraryWithDifferentDefines/includes $(TULSI_BWRS)/_tulsi-includes/x/x/ ";
 				IPHONEOS_DEPLOYMENT_TARGET = 10.0;
-				OTHER_CFLAGS = "-DLIBRARY SECOND DEFINE=2 -DLIBRARY_COPT_DEFINE -DLIBRARY_DEFINES_DEFINE=1 -DLIBRARY_VALUE_WITH_SPACES=Value with spaces -DSubLibraryWithDefines=1 -DSubLibraryWithDefines_DEFINE=SubLibraryWithDefines -DSubLibraryWithDifferentDefines=1";
+				OTHER_CFLAGS = "-D\"LIBRARY SECOND DEFINE=2\" -DLIBRARY_COPT_DEFINE -DLIBRARY_DEFINES_DEFINE=1 -D\"LIBRARY_VALUE_WITH_SPACES=Value with spaces\" -DSubLibraryWithDefines=1 -DSubLibraryWithDefines_DEFINE=SubLibraryWithDefines -DSubLibraryWithDifferentDefines=1";
 				PRODUCT_NAME = _idx_Library_FAFE9183_ios_min10.0;
 				SDKROOT = iphoneos;
 				USER_HEADER_SEARCH_PATHS = "$(TULSI_WR)";
@@ -1372,7 +1372,7 @@
 				GCC_PREPROCESSOR_DEFINITIONS = "NDEBUG=1";
 				HEADER_SEARCH_PATHS = "$(inherited) $(TULSI_WR)/tulsi_e2e_complex/SubLibraryWithDifferentDefines/includes $(TULSI_WR)/_tulsi-includes/x/x/tulsi_e2e_complex/SubLibraryWithDifferentDefines/includes $(TULSI_WR)/_tulsi-includes/x/x/ $(TULSI_BWRS)/tulsi_e2e_complex/SubLibraryWithDifferentDefines/includes $(TULSI_BWRS)/_tulsi-includes/x/x/tulsi_e2e_complex/SubLibraryWithDifferentDefines/includes $(TULSI_BWRS)/_tulsi-includes/x/x/ ";
 				IPHONEOS_DEPLOYMENT_TARGET = 10.0;
-				OTHER_CFLAGS = "-D'SubLibraryWithDifferentDefines Define with spaces and value'=1 -D'SubLibraryWithDifferentDefines Define with spaces' -DSubLibraryWithDifferentDefines=1 -DSubLibraryWithDifferentDefines_INTEGER_DEFINE=1 -DSubLibraryWithDifferentDefines_LocalDefine -DSubLibraryWithDifferentDefines_STRING_DEFINE=Test -DSubLibraryWithDifferentDefines_STRING_WITH_SPACES='String with spaces'";
+				OTHER_CFLAGS = "-D\"SubLibraryWithDifferentDefines_PREQUOTED=Prequoted with spaces\" -D'SubLibraryWithDifferentDefines_SINGLEQUOTED=Single quoted with spaces' -DSubLibraryWithDifferentDefines=1 -DSubLibraryWithDifferentDefines_INTEGER_DEFINE=1 -DSubLibraryWithDifferentDefines_LocalDefine -DSubLibraryWithDifferentDefines_STRING_DEFINE=Test -D\"SubLibraryWithDifferentDefines_STRING_WITH_SPACES=String with spaces\"";
 				PRODUCT_NAME = _idx_SubLibraryWithDifferentDefines_B982A5CC_ios_min10.0;
 				SDKROOT = iphoneos;
 				USER_HEADER_SEARCH_PATHS = "$(TULSI_WR)";
diff --git a/src/TulsiGeneratorTests/PBXTargetGeneratorTests.swift b/src/TulsiGeneratorTests/PBXTargetGeneratorTests.swift
index 7ffaf03..0a7ab5b 100644
--- a/src/TulsiGeneratorTests/PBXTargetGeneratorTests.swift
+++ b/src/TulsiGeneratorTests/PBXTargetGeneratorTests.swift
@@ -2618,6 +2618,40 @@
                           inTargets: targets)
   }
 
+  func testIndexerCFlagsDefinesEscaping() {
+    let package = "test/package"
+
+    let objcTargetName = "ObjcTarget"
+    let objcTargetBuildLabel = BuildLabel("\(package):\(objcTargetName)")
+    let objcTargetDefines = [
+        "A=value with space",
+        "'B=preescaped value'",
+        "\"C=preescaped value\"",
+        "D=nospaces"
+    ] as AnyObject
+
+    let objcLibraryRule = makeTestRuleEntry(objcTargetBuildLabel,
+                                            type: "objc_library",
+                                            attributes: ["compiler_defines": objcTargetDefines],
+                                            sourceFiles: sourceFileNames)
+
+    var processedEntries = [RuleEntry: (NSOrderedSet)]()
+    let indexerTargetName = String(format: "_idx_\(objcTargetName)_%08X_ios_min9.0", objcTargetBuildLabel.hashValue)
+    targetGenerator.registerRuleEntryForIndexer(objcLibraryRule,
+                                                ruleEntryMap: RuleEntryMap(),
+                                                pathFilters: pathFilters,
+                                                processedEntries: &processedEntries)
+    targetGenerator.generateIndexerTargets()
+
+    let targets = project.targetByName
+    XCTAssertEqual(targets.count, 1)
+    validateIndexerTarget(indexerTargetName,
+                          sourceFileNames: sourceFileNames,
+                          otherCFlags: "-D\"C=preescaped value\" -D'B=preescaped value' -D\"A=value with space\" -DD=nospaces",
+                          isSwift: false,
+                          inTargets: targets)
+  }
+
   // MARK: - Helper methods
 
   private func debugBuildSettingsFromSettings(_ settings: [String: String]) -> [String: String] {