Performance improvements (avoid O(n^2) behavior)

This improves performance by avoiding repeatedly traversing and
propagating information up from the build graph (RuleEntries).

This is especially noticable on projects with a lot of targets,
commonly seen with large test_suites.

--
PiperOrigin-RevId: 178781860
MOS_MIGRATED_REVID=178781860
diff --git a/src/TulsiGenerator/Bazel/tulsi/tulsi_aspects.bzl b/src/TulsiGenerator/Bazel/tulsi/tulsi_aspects.bzl
index c532e96..04c0e3f 100644
--- a/src/TulsiGenerator/Bazel/tulsi/tulsi_aspects.bzl
+++ b/src/TulsiGenerator/Bazel/tulsi/tulsi_aspects.bzl
@@ -509,6 +509,7 @@
 
   tulsi_info_files = depset()
   transitive_attributes = dict()
+  transitive_deps_artifacts = depset()
   for attr_name in _TULSI_COMPILE_DEPS:
     deps = _getattr_as_list(rule_attr, attr_name)
     for dep in deps:
@@ -516,6 +517,10 @@
         tulsi_info_files += dep.tulsi_info_files
       if hasattr(dep, 'transitive_attributes'):
         transitive_attributes += dep.transitive_attributes
+      if getattr(dep, 'artifacts', None):
+        transitive_deps_artifacts += dep.artifacts
+      if hasattr(dep, 'transitive_deps_artifacts'):
+        transitive_deps_artifacts += dep.transitive_deps_artifacts
 
   artifacts = _get_opt_attr(target, 'files')
   if artifacts:
@@ -630,6 +635,7 @@
 
   info = _struct_omitting_none(
       artifacts=artifacts,
+      transitive_deps_artifacts=transitive_deps_artifacts.to_list(),
       attr=_struct_omitting_none(**all_attributes),
       build_file=ctx.build_file_path,
       bundle_id=bundle_id,
@@ -661,6 +667,8 @@
   if infoplist:
     tulsi_info_files += [infoplist]
 
+  artifacts_depset = depset(artifacts) if artifacts else depset()
+
   return struct(
       # Matches the --output_groups on the bazel commandline.
       output_groups={
@@ -675,6 +683,10 @@
       # Transitive info that should be applied to every rule that depends on
       # this rule.
       transitive_attributes=transitive_attributes,
+      # Artifacts from this rule.
+      artifacts=artifacts_depset,
+      # Artifacts from the transitive deps of this rule.
+      transitive_deps_artifacts=transitive_deps_artifacts,
   )
 
 
diff --git a/src/TulsiGenerator/BazelAspectInfoExtractor.swift b/src/TulsiGenerator/BazelAspectInfoExtractor.swift
index c4a7bbf..dfb2017 100644
--- a/src/TulsiGenerator/BazelAspectInfoExtractor.swift
+++ b/src/TulsiGenerator/BazelAspectInfoExtractor.swift
@@ -296,6 +296,7 @@
       }
 
       let artifacts = MakeBazelFileInfos("artifacts")
+      let transitiveDepsArtifacts = MakeBazelFileInfos("transitive_deps_artifacts")
       var sources = MakeBazelFileInfos("srcs")
 
       // Appends BazelFileInfo objects to the given array for any info dictionaries representing
@@ -382,6 +383,7 @@
                                 dependencies: dependencies,
                                 frameworkImports: frameworkImports,
                                 secondaryArtifacts: secondaryArtifacts,
+                                transitiveDepsArtifacts: Set(transitiveDepsArtifacts),
                                 extensions: extensions,
                                 bundleID: bundleID,
                                 bundleName: bundleName,
diff --git a/src/TulsiGenerator/PBXTargetGenerator.swift b/src/TulsiGenerator/PBXTargetGenerator.swift
index db571f2..6fbcfd6 100644
--- a/src/TulsiGenerator/PBXTargetGenerator.swift
+++ b/src/TulsiGenerator/PBXTargetGenerator.swift
@@ -75,10 +75,13 @@
   func generateFileReferencesForFilePaths(_ paths: [String], pathFilters: Set<String>?)
 
   /// Registers the given Bazel rule and its transitive dependencies for inclusion by the Xcode
-  /// indexer, adding source files whose directories are present in pathFilters.
-  func registerRuleEntryForIndexer(_ ruleEntries: RuleEntry,
+  /// indexer, adding source files whose directories are present in pathFilters. The rule will
+  /// only be processed if it hasn't already (and therefore isn't in processedEntries).
+  /// - processedEntries: Map of RuleEntry to cumulative preprocessor framework search paths.
+  func registerRuleEntryForIndexer(_ ruleEntry: RuleEntry,
                                    ruleEntryMap: RuleEntryMap,
-                                   pathFilters: Set<String>)
+                                   pathFilters: Set<String>,
+                                   processedEntries: inout [RuleEntry: (NSOrderedSet)])
 
   /// Generates indexer targets for rules that were previously registered through
   /// registerRuleEntryForIndexer. This method may only be called once, after all rule entries have
@@ -448,9 +451,14 @@
     }
   }
 
+  /// Registers the given Bazel rule and its transitive dependencies for inclusion by the Xcode
+  /// indexer, adding source files whose directories are present in pathFilters. The rule will
+  /// only be processed if it hasn't already (and therefore isn't in processedEntries).
+  /// - processedEntries: Map of RuleEntry to cumulative preprocessor framework search paths.
   func registerRuleEntryForIndexer(_ ruleEntry: RuleEntry,
                                    ruleEntryMap: RuleEntryMap,
-                                   pathFilters: Set<String>) {
+                                   pathFilters: Set<String>,
+                                   processedEntries: inout [RuleEntry: (NSOrderedSet)]) {
     let includePathInProject = pathFilterFunc(pathFilters)
     func includeFileInProject(_ info: BazelFileInfo) -> Bool {
       return includePathInProject(info.fullPath)
@@ -468,10 +476,8 @@
       project.getOrCreateGroupsAndFileReferencesForPaths([buildFilePath])
     }
 
-    // Map of build label to cumulative preprocessor framework search paths.
     // TODO(b/63628175): Clean this nested method to also retrieve framework_dir and framework_file
     // from the ObjcProvider, for both static and dynamic frameworks.
-    var processedEntries = [RuleEntry: (NSOrderedSet)]()
     @discardableResult
     func generateIndexerTargetGraphForRuleEntry(_ ruleEntry: RuleEntry) -> (NSOrderedSet) {
       if let data = processedEntries[ruleEntry] {
@@ -797,12 +803,12 @@
       }
 
       switch entry.pbxTargetType {
-        case .Watch2App?:
-          watchAppTargets[name] = (target, entry)
-        case .Watch2Extension?:
-          watchExtensionsByEntry[entry] = target
-        default:
-          break
+      case .Watch2App?:
+        watchAppTargets[name] = (target, entry)
+      case .Watch2Extension?:
+        watchExtensionsByEntry[entry] = target
+      default:
+        break
       }
     }
 
@@ -1556,15 +1562,14 @@
     // removed, but requires changes to LLDB.
     let dSYMEnabled = entry.attributes[.has_swift_dependency] as? Bool ?? false
     buildSettings["TULSI_USE_DSYM"] = dSYMEnabled ? "YES" : "NO"
-    let intermediateArtifacts: [String]
+    let transitiveDepsArtifacts: [String]
     if !dSYMEnabled {
       // For targets that will not generate dSYMs, the set of intermediate libraries generated for
       // dependencies is provided so that downstream utilities may locate them (e.g., to patch DWARF
       // symbols).
-      intermediateArtifacts =
-          entry.discoverIntermediateArtifacts(ruleEntryMap).flatMap({ $0.fullPath }).sorted()
+      transitiveDepsArtifacts = entry.transitiveDepsArtifacts.flatMap({ $0.fullPath }).sorted()
     } else {
-      intermediateArtifacts = []
+      transitiveDepsArtifacts = []
     }
 
     // Disable Xcode's attempts at generating dSYM bundles as it conflicts with the operation of the
@@ -1589,7 +1594,7 @@
                                 first: true)
     }
 
-    return (target, intermediateArtifacts)
+    return (target, transitiveDepsArtifacts)
   }
 
   private func createGenerateSwiftDummyFilesTestBuildPhase() -> PBXShellScriptBuildPhase {
diff --git a/src/TulsiGenerator/RuleEntry.swift b/src/TulsiGenerator/RuleEntry.swift
index ae7fd4e..2166658 100644
--- a/src/TulsiGenerator/RuleEntry.swift
+++ b/src/TulsiGenerator/RuleEntry.swift
@@ -223,6 +223,9 @@
   /// List of implicit artifacts that are generated by this rule.
   public let secondaryArtifacts: [BazelFileInfo]
 
+  /// Transitive list of artifacts produced by the dependencies of this RuleEntry.
+  public let transitiveDepsArtifacts: Set<BazelFileInfo>
+
   /// The Swift language version used by this target.
   public let swiftLanguageVersion: String?
 
@@ -247,10 +250,6 @@
   // of the aspect.
   public var weakDependencies = Set<BuildLabel>()
 
-  /// Transitive set of artifacts produced by the dependencies of this RuleEntry. Note that this
-  /// must be populated via the discoverIntermediateArtifacts method.
-  private(set) public var intermediateArtifacts: Set<BazelFileInfo>? = nil
-
   /// The BUILD file that this rule was defined in.
   public let buildFilePath: String?
 
@@ -327,6 +326,7 @@
        dependencies: Set<String> = Set(),
        frameworkImports: [BazelFileInfo] = [],
        secondaryArtifacts: [BazelFileInfo] = [],
+       transitiveDepsArtifacts: Set<BazelFileInfo> = Set(),
        weakDependencies: Set<BuildLabel>? = nil,
        extensions: Set<BuildLabel>? = nil,
        bundleID: String? = nil,
@@ -366,6 +366,7 @@
     self.dependencies = dependencies
     self.frameworkImports = frameworkImports
     self.secondaryArtifacts = secondaryArtifacts
+    self.transitiveDepsArtifacts = transitiveDepsArtifacts
     if let weakDependencies = weakDependencies {
       self.weakDependencies = weakDependencies
     }
@@ -411,6 +412,7 @@
                    dependencies: Set<String> = Set(),
                    frameworkImports: [BazelFileInfo] = [],
                    secondaryArtifacts: [BazelFileInfo] = [],
+                   transitiveDepsArtifacts: Set<BazelFileInfo> = Set(),
                    weakDependencies: Set<BuildLabel>? = nil,
                    extensions: Set<BuildLabel>? = nil,
                    bundleID: String? = nil,
@@ -435,6 +437,7 @@
               dependencies: dependencies,
               frameworkImports: frameworkImports,
               secondaryArtifacts: secondaryArtifacts,
+              transitiveDepsArtifacts: transitiveDepsArtifacts,
               weakDependencies: weakDependencies,
               extensions: extensions,
               bundleID: bundleID,
@@ -452,26 +455,6 @@
               extensionType: extensionType)
   }
 
-  public func discoverIntermediateArtifacts(_ ruleEntryMap: RuleEntryMap) -> Set<BazelFileInfo> {
-    if intermediateArtifacts != nil { return intermediateArtifacts! }
-
-    var collectedArtifacts = Set<BazelFileInfo>()
-    for dep in dependencies {
-      guard let dependentEntry = ruleEntryMap.ruleEntry(buildLabel: BuildLabel(dep), depender: self) else {
-        // TODO(abaire): Consider making this a standard Tulsi warning.
-        // In theory it shouldn't happen and the unknown dep should be tracked elsewhere.
-        print("Tulsi rule '\(label.value)' - Ignoring unknown dependency '\(dep)'")
-        continue
-      }
-
-      collectedArtifacts.formUnion(dependentEntry.artifacts)
-      collectedArtifacts.formUnion(dependentEntry.discoverIntermediateArtifacts(ruleEntryMap))
-    }
-
-    intermediateArtifacts = collectedArtifacts
-    return intermediateArtifacts!
-  }
-
   // MARK: Private methods
 
   private func parseFileDescriptionListAttribute(_ attribute: RuleEntry.Attribute) -> [BazelFileInfo]? {
diff --git a/src/TulsiGenerator/XcodeProjectGenerator.swift b/src/TulsiGenerator/XcodeProjectGenerator.swift
index 28ddcb2..5640f38 100644
--- a/src/TulsiGenerator/XcodeProjectGenerator.swift
+++ b/src/TulsiGenerator/XcodeProjectGenerator.swift
@@ -350,6 +350,10 @@
     }
 
     profileAction("gathering_sources_for_indexers") {
+      // Map from RuleEntry to cumulative preprocessor framework search paths.
+      // This is used to propagate framework search paths up the graph while also making sure that
+      // each RuleEntry is only registered once.
+      var processedEntries = [RuleEntry: (NSOrderedSet)]()
       let progressNotifier = ProgressNotifier(name: GatheringIndexerSources,
                                               maxValue: expandedTargetLabels.count)
       for label in expandedTargetLabels {
@@ -370,7 +374,8 @@
           autoreleasepool {
             generator.registerRuleEntryForIndexer(ruleEntry,
                                                   ruleEntryMap: ruleEntryMap,
-                                                  pathFilters: config.pathFilters)
+                                                  pathFilters: config.pathFilters,
+                                                  processedEntries: &processedEntries)
           }
         }
       }
diff --git a/src/TulsiGeneratorTests/PBXTargetGeneratorTests.swift b/src/TulsiGeneratorTests/PBXTargetGeneratorTests.swift
index 431bacd..f3f7f42 100644
--- a/src/TulsiGeneratorTests/PBXTargetGeneratorTests.swift
+++ b/src/TulsiGeneratorTests/PBXTargetGeneratorTests.swift
@@ -2105,9 +2105,11 @@
 
   func testGenerateIndexerWithNoSources() {
     let ruleEntry = makeTestRuleEntry("test/app:TestApp", type: "ios_application")
+    var proccessedEntries = [RuleEntry: (NSOrderedSet)]()
     targetGenerator.registerRuleEntryForIndexer(ruleEntry,
                                                 ruleEntryMap: RuleEntryMap(),
-                                                pathFilters: pathFilters)
+                                                pathFilters: pathFilters,
+                                                processedEntries: &proccessedEntries)
     targetGenerator.generateIndexerTargets()
     let targets = project.targetByName
     XCTAssert(targets.isEmpty)
@@ -2118,11 +2120,13 @@
     let ruleEntry = makeTestRuleEntry(buildLabel,
                                       type: "ios_application",
                                       sourceFiles: sourceFileNames)
+    var proccessedEntries = [RuleEntry: (NSOrderedSet)]()
     let indexerTargetName = String(format: "_idx_TestApp_%08X_ios_min9.0", buildLabel.hashValue)
 
     targetGenerator.registerRuleEntryForIndexer(ruleEntry,
                                                 ruleEntryMap: RuleEntryMap(),
-                                                pathFilters: pathFilters)
+                                                pathFilters: pathFilters,
+                                                processedEntries: &proccessedEntries)
     targetGenerator.generateIndexerTargets()
 
     let targets = project.targetByName
@@ -2136,11 +2140,13 @@
                                       type: "ios_application",
                                       attributes: ["pch": ["path": pchFile.path!, "src": true] as AnyObject],
                                       sourceFiles: sourceFileNames)
+    var proccessedEntries = [RuleEntry: (NSOrderedSet)]()
     let indexerTargetName = String(format: "_idx_TestApp_%08X_ios_min9.0", buildLabel.hashValue)
 
     targetGenerator.registerRuleEntryForIndexer(ruleEntry,
                                                 ruleEntryMap: RuleEntryMap(),
-                                                pathFilters: pathFilters)
+                                                pathFilters: pathFilters,
+                                                processedEntries: &proccessedEntries)
     targetGenerator.generateIndexerTargets()
 
     let targets = project.targetByName
@@ -2157,11 +2163,13 @@
                                       type: "ios_binary",
                                       attributes: ruleAttributes as [String : AnyObject],
                                       sourceFiles: sourceFileNames)
+    var proccessedEntries = [RuleEntry: (NSOrderedSet)]()
     let indexerTargetName = String(format: "_idx_TestApp_%08X_ios_min9.0", buildLabel.hashValue)
 
     targetGenerator.registerRuleEntryForIndexer(ruleEntry,
                                                 ruleEntryMap: RuleEntryMap(),
-                                                pathFilters: pathFilters)
+                                                pathFilters: pathFilters,
+                                                processedEntries: &proccessedEntries)
     targetGenerator.generateIndexerTargets()
 
     let targets = project.targetByName
@@ -2184,11 +2192,13 @@
                                       type: "ios_binary",
                                       attributes: ruleAttributes as [String : AnyObject],
                                       sourceFiles: sourceFileNames)
+    var proccessedEntries = [RuleEntry: (NSOrderedSet)]()
     let indexerTargetName = String(format: "_idx_TestApp_%08X_ios_min9.0", buildLabel.hashValue)
 
     targetGenerator.registerRuleEntryForIndexer(ruleEntry,
                                                 ruleEntryMap: RuleEntryMap(),
-                                                pathFilters: pathFilters)
+                                                pathFilters: pathFilters,
+                                                processedEntries: &proccessedEntries)
     targetGenerator.generateIndexerTargets()
 
     let targets = project.targetByName
@@ -2209,11 +2219,13 @@
                                       type: "ios_binary",
                                       attributes: ruleAttributes as [String : AnyObject],
                                       sourceFiles: sourceFileNames)
+    var proccessedEntries = [RuleEntry: (NSOrderedSet)]()
     let indexerTargetName = String(format: "_idx_TestApp_%08X_ios_min9.0", buildLabel.hashValue)
 
     targetGenerator.registerRuleEntryForIndexer(ruleEntry,
                                                 ruleEntryMap: RuleEntryMap(),
-                                                pathFilters: pathFilters.union(Set([dataModel])))
+                                                pathFilters: pathFilters.union(Set([dataModel])),
+                                                processedEntries: &proccessedEntries)
     targetGenerator.generateIndexerTargets()
 
     var allSourceFiles = sourceFileNames
@@ -2238,11 +2250,13 @@
     let ruleEntry = makeTestRuleEntry(buildLabel,
                                       type: "ios_application",
                                       sourceFiles: allSourceFiles)
+    var proccessedEntries = [RuleEntry: (NSOrderedSet)]()
     let indexerTargetName = String(format: "_idx_TestApp_%08X_ios_min9.0", buildLabel.hashValue)
 
     targetGenerator.registerRuleEntryForIndexer(ruleEntry,
                                                 ruleEntryMap: RuleEntryMap(),
-                                                pathFilters: pathFilters)
+                                                pathFilters: pathFilters,
+                                                processedEntries: &proccessedEntries)
     targetGenerator.generateIndexerTargets()
 
     let targets = project.targetByName
@@ -2263,11 +2277,13 @@
     let ruleEntry = makeTestRuleEntry(buildLabel,
                                       type: "ios_application",
                                       sourceFiles: allSourceFiles)
+    var proccessedEntries = [RuleEntry: (NSOrderedSet)]()
     let indexerTargetName = String(format: "_idx_TestApp_%08X_ios_min9.0", buildLabel.hashValue)
 
     targetGenerator.registerRuleEntryForIndexer(ruleEntry,
                                                 ruleEntryMap: RuleEntryMap(),
-                                                pathFilters: pathFilters)
+                                                pathFilters: pathFilters,
+                                                processedEntries: &proccessedEntries)
     targetGenerator.generateIndexerTargets()
 
     let targets = project.targetByName
@@ -2283,9 +2299,11 @@
                                       type: "ios_application",
                                       sourceFiles: sourceFileNames,
                                       buildFilePath: buildFilePath)
+    var proccessedEntries = [RuleEntry: (NSOrderedSet)]()
     targetGenerator.registerRuleEntryForIndexer(ruleEntry,
                                                 ruleEntryMap: RuleEntryMap(),
-                                                pathFilters: pathFilters)
+                                                pathFilters: pathFilters,
+                                                processedEntries: &proccessedEntries)
     targetGenerator.generateIndexerTargets()
     XCTAssertNil(fileRefForPath(buildFilePath))
   }
@@ -2298,9 +2316,11 @@
                                       type: "ios_application",
                                       sourceFiles: sourceFileNames,
                                       buildFilePath: buildFilePath)
+    var proccessedEntries = [RuleEntry: (NSOrderedSet)]()
     targetGenerator.registerRuleEntryForIndexer(ruleEntry,
                                                 ruleEntryMap: RuleEntryMap(),
-                                                pathFilters: pathFilters)
+                                                pathFilters: pathFilters,
+                                                processedEntries: &proccessedEntries)
     targetGenerator.generateIndexerTargets()
     XCTAssertNotNil(fileRefForPath(buildFilePath))
   }
@@ -2313,9 +2333,11 @@
                                       type: "ios_application",
                                       sourceFiles: sourceFileNames,
                                       buildFilePath: buildFilePath)
+    var proccessedEntries = [RuleEntry: (NSOrderedSet)]()
     targetGenerator.registerRuleEntryForIndexer(ruleEntry,
                                                 ruleEntryMap: RuleEntryMap(),
-                                                pathFilters: pathFilters)
+                                                pathFilters: pathFilters,
+                                                processedEntries: &proccessedEntries)
     targetGenerator.generateIndexerTargets()
     XCTAssertNotNil(fileRefForPath(buildFilePath))
   }
@@ -2328,9 +2350,11 @@
                                        type: "ios_binary",
                                        attributes: ["pch": ["path": pchFile.path!, "src": true] as AnyObject],
                                        sourceFiles: sourceFiles1)
+    var proccessedEntries = [RuleEntry: (NSOrderedSet)]()
     targetGenerator.registerRuleEntryForIndexer(ruleEntry1,
                                                 ruleEntryMap: RuleEntryMap(),
-                                                pathFilters: pathFilters)
+                                                pathFilters: pathFilters,
+                                                processedEntries: &proccessedEntries)
 
     let sourceFiles2 = ["2.swift"]
     let buildLabel2 = BuildLabel("test/app:TestLibrary")
@@ -2340,7 +2364,8 @@
                                        sourceFiles: sourceFiles2)
     targetGenerator.registerRuleEntryForIndexer(ruleEntry2,
                                                 ruleEntryMap: RuleEntryMap(),
-                                                pathFilters: pathFilters)
+                                                pathFilters: pathFilters,
+                                                processedEntries: &proccessedEntries)
     targetGenerator.generateIndexerTargets()
 
     let targets = project.targetByName
@@ -2362,9 +2387,11 @@
                                        type: "ios_binary",
                                        attributes: ["pch": ["path": pchFile.path!, "src": true] as AnyObject],
                                        sourceFiles: sourceFiles1)
+    var proccessedEntries = [RuleEntry: (NSOrderedSet)]()
     targetGenerator.registerRuleEntryForIndexer(ruleEntry1,
                                                 ruleEntryMap: RuleEntryMap(),
-                                                pathFilters: pathFilters)
+                                                pathFilters: pathFilters,
+                                                processedEntries: &proccessedEntries)
     targetGenerator.generateIndexerTargets()
 
     let targets = project.targetByName
@@ -2387,9 +2414,11 @@
                                        type: "ios_binary",
                                        attributes: ["pch": ["path": pchFile.path!, "src": true] as AnyObject],
                                        sourceFiles: sourceFiles1)
+    var proccessedEntries = [RuleEntry: (NSOrderedSet)]()
     targetGenerator.registerRuleEntryForIndexer(ruleEntry1,
                                                 ruleEntryMap: RuleEntryMap(),
-                                                pathFilters: pathFilters)
+                                                pathFilters: pathFilters,
+                                                processedEntries: &proccessedEntries)
 
     let sourceFiles2 = ["2.swift"]
     let buildTargetName2 = String(repeating: "B", count: 255)
@@ -2400,7 +2429,8 @@
                                        sourceFiles: sourceFiles2)
     targetGenerator.registerRuleEntryForIndexer(ruleEntry2,
                                                 ruleEntryMap: RuleEntryMap(),
-                                                pathFilters: pathFilters)
+                                                pathFilters: pathFilters,
+                                                processedEntries: &proccessedEntries)
     targetGenerator.generateIndexerTargets()
 
     let targets = project.targetByName
@@ -2421,10 +2451,12 @@
                                        type: "ios_binary",
                                        attributes: ["pch": ["path": pchFile.path!, "src": true] as AnyObject],
                                        sourceFiles: sourceFileNames)
+    var proccessedEntries = [RuleEntry: (NSOrderedSet)]()
     let indexer1TargetName = String(format: "_idx_TestBinary_%08X_ios_min9.0", buildLabel1.hashValue)
     targetGenerator.registerRuleEntryForIndexer(ruleEntry1,
                                                 ruleEntryMap: RuleEntryMap(),
-                                                pathFilters: pathFilters)
+                                                pathFilters: pathFilters,
+                                                processedEntries: &proccessedEntries)
 
     let buildLabel2 = BuildLabel("test/app:TestLibrary")
     let ruleEntry2 = makeTestRuleEntry(buildLabel2,
@@ -2434,7 +2466,8 @@
     let indexer2TargetName = String(format: "_idx_TestLibrary_%08X_ios_min9.0", buildLabel2.hashValue)
     targetGenerator.registerRuleEntryForIndexer(ruleEntry2,
                                                 ruleEntryMap: RuleEntryMap(),
-                                                pathFilters: pathFilters)
+                                                pathFilters: pathFilters,
+                                                processedEntries: &proccessedEntries)
     targetGenerator.generateIndexerTargets()
 
     let targets = project.targetByName
@@ -2460,10 +2493,12 @@
                                        type: "ios_binary",
                                        attributes: ruleAttributes1 as [String : AnyObject],
                                        sourceFiles: sourceFileNames)
+    var proccessedEntries = [RuleEntry: (NSOrderedSet)]()
     let indexer1TargetName = String(format: "_idx_TestBinary_%08X_ios_min9.0", buildLabel1.hashValue)
     targetGenerator.registerRuleEntryForIndexer(ruleEntry1,
                                                 ruleEntryMap: RuleEntryMap(),
-                                                pathFilters: pathFilters)
+                                                pathFilters: pathFilters,
+                                                processedEntries: &proccessedEntries)
 
     let buildLabel2 = BuildLabel("test/app:TestLibrary")
     let ruleEntry2 = makeTestRuleEntry(buildLabel2,
@@ -2473,7 +2508,8 @@
     let indexer2TargetName = String(format: "_idx_TestLibrary_%08X_ios_min9.0", buildLabel2.hashValue)
     targetGenerator.registerRuleEntryForIndexer(ruleEntry2,
                                                 ruleEntryMap: RuleEntryMap(),
-                                                pathFilters: pathFilters)
+                                                pathFilters: pathFilters,
+                                                processedEntries: &proccessedEntries)
     targetGenerator.generateIndexerTargets()
 
     let targets = project.targetByName
diff --git a/src/TulsiGeneratorTests/XcodeProjectGeneratorTests.swift b/src/TulsiGeneratorTests/XcodeProjectGeneratorTests.swift
index 53aada2..7ca11c6 100644
--- a/src/TulsiGeneratorTests/XcodeProjectGeneratorTests.swift
+++ b/src/TulsiGeneratorTests/XcodeProjectGeneratorTests.swift
@@ -432,7 +432,8 @@
 
   func registerRuleEntryForIndexer(_ ruleEntry: RuleEntry,
                                    ruleEntryMap: RuleEntryMap,
-                                   pathFilters: Set<String>) {
+                                   pathFilters: Set<String>,
+                                   processedEntries: inout [RuleEntry: (NSOrderedSet)]) {
   }
 
   func generateIndexerTargets() -> [String: PBXTarget] {