cmGlobalVisualStudio7Generator: Factor folder collection out of write method
diff --git a/Source/cmGlobalVisualStudio14Generator.cxx b/Source/cmGlobalVisualStudio14Generator.cxx
index 5d4ebbd..5c526c7 100644
--- a/Source/cmGlobalVisualStudio14Generator.cxx
+++ b/Source/cmGlobalVisualStudio14Generator.cxx
@@ -522,7 +522,8 @@
   return std::string();
 }
 
-void cmGlobalVisualStudio14Generator::AddSolutionItems(cmLocalGenerator* root)
+void cmGlobalVisualStudio14Generator::AddSolutionItems(cmLocalGenerator* root,
+                                                       VSFolders& vsFolders)
 {
   cmValue n = root->GetMakefile()->GetProperty("VS_SOLUTION_ITEMS");
   if (cmNonempty(n)) {
@@ -552,11 +553,11 @@
         std::string folderPath = sg->GetFullName();
         // Source groups use '\' while solution folders use '/'.
         cmSystemTools::ReplaceString(folderPath, "\\", "/");
-        folder = this->CreateSolutionFolders(folderPath);
+        folder = vsFolders.Create(folderPath);
       } else {
         // Lazily initialize the default solution items folder.
         if (defaultFolder == nullptr) {
-          defaultFolder = this->CreateSolutionFolders("Solution Items");
+          defaultFolder = vsFolders.Create("Solution Items");
         }
         folder = defaultFolder;
       }
diff --git a/Source/cmGlobalVisualStudio14Generator.h b/Source/cmGlobalVisualStudio14Generator.h
index aed5de6..3f73574 100644
--- a/Source/cmGlobalVisualStudio14Generator.h
+++ b/Source/cmGlobalVisualStudio14Generator.h
@@ -66,7 +66,7 @@
 
   std::string GetWindows10SDKVersion(cmMakefile* mf);
 
-  void AddSolutionItems(cmLocalGenerator* root) override;
+  void AddSolutionItems(cmLocalGenerator* root, VSFolders& vsFolders) override;
 
   void WriteFolderSolutionItems(std::ostream& fout,
                                 cmVisualStudioFolder const& folder) override;
diff --git a/Source/cmGlobalVisualStudio71Generator.cxx b/Source/cmGlobalVisualStudio71Generator.cxx
index bb6ffe7..5f00bda 100644
--- a/Source/cmGlobalVisualStudio71Generator.cxx
+++ b/Source/cmGlobalVisualStudio71Generator.cxx
@@ -25,7 +25,8 @@
 
 void cmGlobalVisualStudio71Generator::WriteSLNFile(
   std::ostream& fout, cmLocalGenerator* root,
-  OrderedTargetDependSet const& orderedProjectTargets)
+  OrderedTargetDependSet const& orderedProjectTargets,
+  VSFolders const& vsFolders)
 {
   std::vector<std::string> configs =
     root->GetMakefile()->GetGeneratorConfigs(cmMakefile::ExcludeEmptyConfig);
@@ -33,21 +34,13 @@
   // Write out the header for a SLN file
   this->WriteSLNHeader(fout);
 
-  // Generate the targets specification to a string.  We will put this in
-  // the actual .sln file later.  As a side effect, this method also
-  // populates the set of folders.
-  std::ostringstream targetsSlnString;
-  this->WriteTargetsToSolution(targetsSlnString, root, orderedProjectTargets);
-
-  this->AddSolutionItems(root);
-
   // Generate folder specification.
-  if (!this->VisualStudioFolders.empty()) {
-    this->WriteFolders(fout);
+  if (!vsFolders.Folders.empty()) {
+    this->WriteFolders(fout, vsFolders);
   }
 
   // Now write the actual target specification content.
-  fout << targetsSlnString.str();
+  this->WriteTargetsToSolution(fout, root, orderedProjectTargets);
 
   // Write out the configurations information for the solution
   fout << "Global\n";
@@ -59,10 +52,10 @@
   this->WriteTargetConfigurations(fout, configs, orderedProjectTargets);
   fout << "\tEndGlobalSection\n";
 
-  if (!this->VisualStudioFolders.empty()) {
+  if (!vsFolders.Folders.empty()) {
     // Write out project folders
     fout << "\tGlobalSection(NestedProjects) = preSolution\n";
-    this->WriteFoldersContent(fout);
+    this->WriteFoldersContent(fout, vsFolders);
     fout << "\tEndGlobalSection\n";
   }
 
diff --git a/Source/cmGlobalVisualStudio71Generator.h b/Source/cmGlobalVisualStudio71Generator.h
index dac7caa..d25b520 100644
--- a/Source/cmGlobalVisualStudio71Generator.h
+++ b/Source/cmGlobalVisualStudio71Generator.h
@@ -28,9 +28,9 @@
   cmGlobalVisualStudio71Generator(cmake* cm);
 
 protected:
-  void WriteSLNFile(
-    std::ostream& fout, cmLocalGenerator* root,
-    OrderedTargetDependSet const& orderedProjectTargets) override;
+  void WriteSLNFile(std::ostream& fout, cmLocalGenerator* root,
+                    OrderedTargetDependSet const& orderedProjectTargets,
+                    VSFolders const& vsFolders) override;
   virtual void WriteSolutionConfigurations(
     std::ostream& fout, std::vector<std::string> const& configs);
   void WriteProject(std::ostream& fout, std::string const& name,
diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx
index c733581..e52eca2 100644
--- a/Source/cmGlobalVisualStudio7Generator.cxx
+++ b/Source/cmGlobalVisualStudio7Generator.cxx
@@ -325,13 +325,16 @@
   OrderedTargetDependSet orderedProjectTargets(
     projectTargets, this->GetStartupProjectName(root));
 
+  VSFolders vsFolders = this->CreateSolutionFolders(orderedProjectTargets);
+  this->AddSolutionItems(root, vsFolders);
+
   std::string fname = GetSLNFile(root);
   cmGeneratedFileStream fout(fname);
   fout.SetCopyIfDifferent(true);
   if (!fout) {
     return;
   }
-  this->WriteSLNFile(fout, root, orderedProjectTargets);
+  this->WriteSLNFile(fout, root, orderedProjectTargets, vsFolders);
   if (fout.Close()) {
     this->FileReplacedDuringGenerate(fname);
   }
@@ -382,7 +385,29 @@
   }
 }
 
-cmVisualStudioFolder* cmGlobalVisualStudio7Generator::CreateSolutionFolders(
+cmGlobalVisualStudio7Generator::VSFolders
+cmGlobalVisualStudio7Generator::CreateSolutionFolders(
+  OrderedTargetDependSet const& orderedProjectTargets)
+{
+  VSFolders vsFolders;
+  if (!this->UseFolderProperty()) {
+    return vsFolders;
+  }
+  for (cmGeneratorTarget const* target : orderedProjectTargets) {
+    if (this->IsInSolution(target) &&
+        (target->GetProperty("EXTERNAL_MSPROJECT") ||
+         target->GetProperty("GENERATOR_FILE_NAME"))) {
+      // Create "solution folder" information from FOLDER target property
+      if (cmVisualStudioFolder* folder =
+            vsFolders.Create(target->GetEffectiveFolderName())) {
+        folder->Projects.insert(target->GetName());
+      }
+    }
+  }
+  return vsFolders;
+}
+
+cmVisualStudioFolder* cmGlobalVisualStudio7Generator::VSFolders::Create(
   std::string const& path)
 {
   if (path.empty()) {
@@ -402,7 +427,7 @@
     if (cumulativePath.empty()) {
       cumulativePath = cmStrCat("CMAKE_FOLDER_GUID_", iter);
     } else {
-      this->VisualStudioFolders[cumulativePath].Projects.insert(
+      this->Folders[cumulativePath].Projects.insert(
         cmStrCat(cumulativePath, '/', iter));
 
       cumulativePath = cmStrCat(cumulativePath, '/', iter);
@@ -413,15 +438,13 @@
     return nullptr;
   }
 
-  return &this->VisualStudioFolders[cumulativePath];
+  return &this->Folders[cumulativePath];
 }
 
 void cmGlobalVisualStudio7Generator::WriteTargetsToSolution(
   std::ostream& fout, cmLocalGenerator* root,
   OrderedTargetDependSet const& projectTargets)
 {
-  VisualStudioFolders.clear();
-
   std::vector<std::string> configs =
     root->GetMakefile()->GetGeneratorConfigs(cmMakefile::ExcludeEmptyConfig);
 
@@ -429,8 +452,6 @@
     if (!this->IsInSolution(target)) {
       continue;
     }
-    bool written = false;
-
     // handle external vc project files
     cmValue expath = target->GetProperty("EXTERNAL_MSPROJECT");
     if (expath) {
@@ -440,7 +461,6 @@
       this->WriteExternalProject(fout, project, location,
                                  target->GetProperty("VS_PROJECT_TYPE"),
                                  target->GetUtilities());
-      written = true;
     } else {
       cmValue vcprojName = target->GetProperty("GENERATOR_FILE_NAME");
       if (vcprojName) {
@@ -451,28 +471,17 @@
           dir.clear(); // msbuild cannot handle ".\" prefix
         }
         this->WriteProject(fout, *vcprojName, dir, target);
-        written = true;
-      }
-    }
-
-    // Create "solution folder" information from FOLDER target property
-    //
-    if (written && this->UseFolderProperty()) {
-      cmVisualStudioFolder* folder =
-        this->CreateSolutionFolders(target->GetEffectiveFolderName());
-
-      if (folder != nullptr) {
-        folder->Projects.insert(target->GetName());
       }
     }
   }
 }
 
-void cmGlobalVisualStudio7Generator::WriteFolders(std::ostream& fout)
+void cmGlobalVisualStudio7Generator::WriteFolders(std::ostream& fout,
+                                                  VSFolders const& vsFolders)
 {
   cm::string_view const prefix = "CMAKE_FOLDER_GUID_";
   std::string guidProjectTypeFolder = "2150E333-8FDC-42A3-9474-1A3956D46DE8";
-  for (auto const& iter : VisualStudioFolders) {
+  for (auto const& iter : vsFolders.Folders) {
     std::string fullName = iter.first;
     std::string guid = this->GetGUID(fullName);
 
@@ -494,9 +503,10 @@
   }
 }
 
-void cmGlobalVisualStudio7Generator::WriteFoldersContent(std::ostream& fout)
+void cmGlobalVisualStudio7Generator::WriteFoldersContent(
+  std::ostream& fout, VSFolders const& vsFolders)
 {
-  for (auto const& iter : VisualStudioFolders) {
+  for (auto const& iter : vsFolders.Folders) {
     std::string key(iter.first);
     std::string guidParent(this->GetGUID(key));
 
diff --git a/Source/cmGlobalVisualStudio7Generator.h b/Source/cmGlobalVisualStudio7Generator.h
index 4a6da53..f1ae133 100644
--- a/Source/cmGlobalVisualStudio7Generator.h
+++ b/Source/cmGlobalVisualStudio7Generator.h
@@ -134,6 +134,12 @@
 
   void Generate() override;
 
+  struct VSFolders
+  {
+    std::map<std::string, cmVisualStudioFolder> Folders;
+    cmVisualStudioFolder* Create(std::string const& path);
+  };
+
   std::string const& GetDevEnvCommand();
   virtual std::string FindDevEnvCommand();
 
@@ -143,7 +149,8 @@
                              std::vector<cmLocalGenerator*>& generators);
   virtual void WriteSLNFile(
     std::ostream& fout, cmLocalGenerator* root,
-    OrderedTargetDependSet const& orderedProjectTargets) = 0;
+    OrderedTargetDependSet const& orderedProjectTargets,
+    VSFolders const& vsFolders) = 0;
   virtual void WriteProject(std::ostream& fout, std::string const& name,
                             std::string const& path,
                             cmGeneratorTarget const* t) = 0;
@@ -160,7 +167,8 @@
   virtual void WriteSLNFooter(std::ostream& fout);
   std::string WriteUtilityDepend(cmGeneratorTarget const* target) override;
 
-  cmVisualStudioFolder* CreateSolutionFolders(std::string const& path);
+  VSFolders CreateSolutionFolders(
+    OrderedTargetDependSet const& orderedProjectTargets);
 
   virtual void WriteTargetsToSolution(
     std::ostream& fout, cmLocalGenerator* root,
@@ -184,15 +192,15 @@
                     cmGeneratorTarget const* target);
   std::map<std::string, std::string> GUIDMap;
 
-  virtual void WriteFolders(std::ostream& fout);
-  virtual void WriteFoldersContent(std::ostream& fout);
+  virtual void WriteFolders(std::ostream& fout, VSFolders const& vsFolders);
+  virtual void WriteFoldersContent(std::ostream& fout,
+                                   VSFolders const& vsFolders);
 
-  virtual void AddSolutionItems(cmLocalGenerator* root) = 0;
+  virtual void AddSolutionItems(cmLocalGenerator* root,
+                                VSFolders& vsFolders) = 0;
   virtual void WriteFolderSolutionItems(
     std::ostream& fout, cmVisualStudioFolder const& folder) = 0;
 
-  std::map<std::string, cmVisualStudioFolder> VisualStudioFolders;
-
   bool MarmasmEnabled;
   bool MasmEnabled;
   bool NasmEnabled;