Repository: apple/swift
File: unittests/DependencyScan/ModuleDeps.cpp (C++)

Code before:
  std::string SerializedDiagnosticsOutputPath =
      createFilename(OutputDirPath, "scan-diags.dia");

  // Create imported module Swift interface files
  ASSERT_FALSE(emitFileWithContents(SwiftDirPath, "A.swiftinterface",
                                    "// swift-interface-format-version: 1.0\n\
// swift-module-flags: -module-name A\n\
import Swift\n\
#error(\"This is an error\")\n\
public func funcA() { }\n"));

  // Paths to shims and stdlib
  llvm::SmallString<128> ShimsLibDir = StdLibDir;
  llvm::sys::path::append(ShimsLibDir, "shims");
  auto Target = llvm::Triple(llvm::sys::getDefaultTargetTriple());
  llvm::sys::path::append(StdLibDir, getPlatformNameForTriple(Target));

  // Generate command line
  std::vector<std::string> CommandStr = {
      TestPathStr,
      "-I", SwiftDirPath,
      "-I", StdLibDir.str().str(),
      "-I", ShimsLibDir.str().str(),
      "-serialize-diagnostics-path", SerializedDiagnosticsOutputPath,
      "-module-name", "testSerializedDiagnosticOutput"};
  // On Windows we need to add an extra escape for path separator characters
  // because otherwise the command line tokenizer will treat them as escape
  // characters.
  for (size_t i = 0; i < CommandStr.size(); ++i) {
    std::replace(CommandStr[i].begin(), CommandStr[i].end(), '\\', '/');
  }
  std::vector<const char *> Command;
  for (auto &command : CommandStr)
    Command.push_back(command.c_str());

  {
    auto ScanningService = std::make_unique<SwiftDependencyScanningService>();
    std::vector<DepScanInMemoryDiagnosticCollector::ScannerDiagnosticInfo>
        InitializationDiagnostics;
    auto QueryContext = ScannerTool.createScanQueryContext(Command, {},
                                                           InitializationDiagnostics);
    ASSERT_FALSE(QueryContext.getError());

    ModuleDependenciesCache ScanCache(
        QueryContext->ScanInstance.get()->getMainModule()->getNameStr().str(),
        QueryContext->ScanInstance.get()
            ->getInvocation()
            .getModuleScanningHash());
    auto DependenciesOrErr =
        performModuleScan(*ScanningService, ScanCache, *QueryContext);


Review comment (security):
I suggest add a test in this format but with escaped white space like `"Program\ Files"` and make sure that parse. It can even be an include path without properly modeled on FileSystem since a bad tokenization will just break the entire parsing.

Code after:
  ASSERT_FALSE(llvm::sys::fs::create_directory(OutputDirPath));
  std::string SerializedDiagnosticsOutputPath =
      createFilename(OutputDirPath, "scan-diags.dia");

  // Create imported module Swift interface files
  ASSERT_FALSE(emitFileWithContents(SwiftDirPath, "A.swiftinterface",
                                    "// swift-interface-format-version: 1.0\n\
// swift-module-flags: -module-name A\n\
import Swift\n\
#error(\"This is an error\")\n\
public func funcA() { }\n"));

  // Paths to shims and stdlib
  llvm::SmallString<128> ShimsLibDir = StdLibDir;
  llvm::sys::path::append(ShimsLibDir, "shims");
  auto Target = llvm::Triple(llvm::sys::getDefaultTargetTriple());
  llvm::sys::path::append(StdLibDir, getPlatformNameForTriple(Target));

  // Generate command line
  std::vector<std::string> CommandStr = {
      TestPathStr,
      "-I", SwiftDirPath,
      "-I", StdLibDir.str().str(),
      "-I", ShimsLibDir.str().str(),
      "-serialize-diagnostics-path", SerializedDiagnosticsOutputPath,
      "-module-name", "testSerializedDiagnosticOutput"};
  // On Windows we need to add an extra escape for path separator characters
  // because otherwise the command line tokenizer will treat them as escape
  // characters.
  for (size_t i = 0; i < CommandStr.size(); ++i) {
    std::replace(CommandStr[i].begin(), CommandStr[i].end(), '\\', '/');
  }
  std::vector<const char *> Command;
  for (auto &command : CommandStr)
    Command.push_back(command.c_str());

  {
    auto ScanningService = std::make_unique<SwiftDependencyScanningService>();
    std::vector<DepScanInMemoryDiagnosticCollector::ScannerDiagnosticInfo>
        InitializationDiagnostics;
    auto QueryContext = ScannerTool.createScanQueryContext(Command, {},
                                                           InitializationDiagnostics);
    ASSERT_FALSE(QueryContext.getError());

    ModuleDependenciesCache ScanCache(
        QueryContext->ScanInstance.get()->getMainModule()->getNameStr().str(),
        QueryContext->ScanInstance.get()
            ->getInvocation()
            .getModuleScanningHash());
    auto DependenciesOrErr =
        performModuleScan(*ScanningService, ScanCache, *QueryContext);