ahatanak updated this revision to Diff 480101.
ahatanak marked an inline comment as done.
ahatanak added a comment.

Add another environment variable `CC_PRINT_HEADERS_FILTERING`, which can be 
used to specify whether header information should be filtered or not.

Currently, `CC_PRINT_HEADERS_FORMAT=json, CC_PRINT_HEADERS_FILTERING=on` and 
`CC_PRINT_HEADERS_FORMAT=textual, CC_PRINT_HEADERS_FILTERING=off` are allowed. 
`CC_PRINT_HEADERS=1` gets translated to `CC_PRINT_HEADERS_FORMAT=textual, 
CC_PRINT_HEADERS_FILTERING=off`.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D137996/new/

https://reviews.llvm.org/D137996

Files:
  clang/include/clang/Basic/HeaderIncludeFormatKind.h
  clang/include/clang/Driver/Driver.h
  clang/include/clang/Driver/Options.td
  clang/include/clang/Frontend/DependencyOutputOptions.h
  clang/lib/Driver/Driver.cpp
  clang/lib/Driver/ToolChains/Clang.cpp
  clang/lib/Frontend/HeaderIncludeGen.cpp
  clang/test/Preprocessor/Inputs/print-header-json/header0.h
  clang/test/Preprocessor/Inputs/print-header-json/header1.h
  clang/test/Preprocessor/Inputs/print-header-json/header2.h
  clang/test/Preprocessor/Inputs/print-header-json/system/system0.h
  clang/test/Preprocessor/Inputs/print-header-json/system/system1.h
  clang/test/Preprocessor/Inputs/print-header-json/system/system2.h
  clang/test/Preprocessor/Inputs/print-header-json/system/system3.h
  clang/test/Preprocessor/print-header-json.c
  clang/tools/driver/driver.cpp

Index: clang/tools/driver/driver.cpp
===================================================================
--- clang/tools/driver/driver.cpp
+++ clang/tools/driver/driver.cpp
@@ -13,6 +13,7 @@
 
 #include "clang/Driver/Driver.h"
 #include "clang/Basic/DiagnosticOptions.h"
+#include "clang/Basic/HeaderIncludeFormatKind.h"
 #include "clang/Basic/Stack.h"
 #include "clang/Config/config.h"
 #include "clang/Driver/Compilation.h"
@@ -243,29 +244,54 @@
       *NumberSignPtr = '=';
 }
 
-static void SetBackdoorDriverOutputsFromEnvVars(Driver &TheDriver) {
-  auto CheckEnvVar = [](const char *EnvOptSet, const char *EnvOptFile,
-                        std::string &OptFile) {
-    bool OptSet = !!::getenv(EnvOptSet);
-    if (OptSet) {
-      if (const char *Var = ::getenv(EnvOptFile))
-        OptFile = Var;
-    }
-    return OptSet;
-  };
+template <class T>
+static T checkEnvVar(const char *EnvOptSet, const char *EnvOptFile,
+                     std::string &OptFile) {
+  T OptVal = ::getenv(EnvOptSet);
+  if (OptVal) {
+    if (const char *Var = ::getenv(EnvOptFile))
+      OptFile = Var;
+  }
+  return OptVal;
+}
 
+static bool SetBackdoorDriverOutputsFromEnvVars(Driver &TheDriver) {
   TheDriver.CCPrintOptions =
-      CheckEnvVar("CC_PRINT_OPTIONS", "CC_PRINT_OPTIONS_FILE",
-                  TheDriver.CCPrintOptionsFilename);
-  TheDriver.CCPrintHeaders =
-      CheckEnvVar("CC_PRINT_HEADERS", "CC_PRINT_HEADERS_FILE",
-                  TheDriver.CCPrintHeadersFilename);
+      checkEnvVar<bool>("CC_PRINT_OPTIONS", "CC_PRINT_OPTIONS_FILE",
+                        TheDriver.CCPrintOptionsFilename);
+  if (checkEnvVar<bool>("CC_PRINT_HEADERS", "CC_PRINT_HEADERS_FILE",
+                        TheDriver.CCPrintHeadersFilename)) {
+    TheDriver.CCPrintHeadersFormat = HIF_Textual;
+    TheDriver.CCPrintHeadersFiltering = false;
+  } else if (const char *EnvVar = checkEnvVar<const char *>(
+                 "CC_PRINT_HEADERS_FORMAT", "CC_PRINT_HEADERS_FILE",
+                 TheDriver.CCPrintHeadersFilename)) {
+    TheDriver.CCPrintHeadersFormat = stringToHeaderIncludeFormatKind(EnvVar);
+    const char *FilteringStr = ::getenv("CC_PRINT_HEADERS_FILTERING");
+    unsigned Filtering;
+    if (!stringToHeaderIncludeFiltering(FilteringStr, Filtering)) {
+      llvm::errs() << "error: CC_PRINT_HEADERS_FILTERING incorrect or not set";
+      return false;
+    }
+    if ((TheDriver.CCPrintHeadersFormat == HIF_Textual && Filtering) ||
+        (TheDriver.CCPrintHeadersFormat == HIF_JSON && !Filtering)) {
+      llvm::errs()
+          << "error: unsupported configuration: "
+             "(CC_PRINT_HEADERS_FORMAT, CC_PRINT_HEADERS_FILTERING) = ("
+          << EnvVar << ", " << FilteringStr << ")\n";
+      return false;
+    }
+    TheDriver.CCPrintHeadersFiltering = Filtering;
+  }
+
   TheDriver.CCLogDiagnostics =
-      CheckEnvVar("CC_LOG_DIAGNOSTICS", "CC_LOG_DIAGNOSTICS_FILE",
-                  TheDriver.CCLogDiagnosticsFilename);
+      checkEnvVar<bool>("CC_LOG_DIAGNOSTICS", "CC_LOG_DIAGNOSTICS_FILE",
+                        TheDriver.CCLogDiagnosticsFilename);
   TheDriver.CCPrintProcessStats =
-      CheckEnvVar("CC_PRINT_PROC_STAT", "CC_PRINT_PROC_STAT_FILE",
-                  TheDriver.CCPrintStatReportFilename);
+      checkEnvVar<bool>("CC_PRINT_PROC_STAT", "CC_PRINT_PROC_STAT_FILE",
+                        TheDriver.CCPrintStatReportFilename);
+
+  return true;
 }
 
 static void FixupDiagPrefixExeName(TextDiagnosticPrinter *DiagClient,
@@ -480,7 +506,8 @@
 
   insertTargetAndModeArgs(TargetAndMode, Args, SavedStrings);
 
-  SetBackdoorDriverOutputsFromEnvVars(TheDriver);
+  if (!SetBackdoorDriverOutputsFromEnvVars(TheDriver))
+    return 1;
 
   if (!UseNewCC1Process) {
     TheDriver.CC1Main = &ExecuteCC1Tool;
Index: clang/test/Preprocessor/print-header-json.c
===================================================================
--- /dev/null
+++ clang/test/Preprocessor/print-header-json.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -E -header-include-format=json -header-include-filtering=on -header-include-file %t.txt -I %S/Inputs/print-header-json -isystem %S/Inputs/print-header-json/system %s -o /dev/null
+// RUN: cat %t.txt | FileCheck %s
+// RUN: rm %t.txt
+// RUN: env CC_PRINT_HEADERS_FORMAT=json CC_PRINT_HEADERS_FILTERING=on CC_PRINT_HEADERS_FILE=%t.txt %clang -fsyntax-only -I %S/Inputs/print-header-json -isystem %S/Inputs/print-header-json/system %s -o /dev/null
+// RUN: cat %t.txt | FileCheck %s
+
+#include "system0.h"
+#include "header0.h"
+#include "system2.h"
+
+// CHECK: {"source":"{{[^,]*}}/print-header-json.c","includes":["{{[^,]*}}system0.h","{{[^,]*}}system3.h","{{[^,]*}}system2.h"]}
Index: clang/test/Preprocessor/Inputs/print-header-json/system/system0.h
===================================================================
--- /dev/null
+++ clang/test/Preprocessor/Inputs/print-header-json/system/system0.h
@@ -0,0 +1,2 @@
+#include "system1.h"
+#include "system2.h"
Index: clang/test/Preprocessor/Inputs/print-header-json/header0.h
===================================================================
--- /dev/null
+++ clang/test/Preprocessor/Inputs/print-header-json/header0.h
@@ -0,0 +1,3 @@
+#include "system3.h"
+#include "header1.h"
+#include "header2.h"
Index: clang/lib/Frontend/HeaderIncludeGen.cpp
===================================================================
--- clang/lib/Frontend/HeaderIncludeGen.cpp
+++ clang/lib/Frontend/HeaderIncludeGen.cpp
@@ -12,6 +12,7 @@
 #include "clang/Frontend/FrontendDiagnostic.h"
 #include "clang/Lex/Preprocessor.h"
 #include "llvm/ADT/SmallString.h"
+#include "llvm/Support/JSON.h"
 #include "llvm/Support/raw_ostream.h"
 using namespace clang;
 
@@ -49,6 +50,43 @@
   void FileSkipped(const FileEntryRef &SkippedFile, const Token &FilenameTok,
                    SrcMgr::CharacteristicKind FileType) override;
 };
+
+/// A callback for emitting header usage information to a file in JSON. Each
+/// line in the file is a JSON object that includes the source file name and
+/// the list of headers directly or indirectly included from it. For example:
+///
+/// {"source":"/tmp/foo.c",
+///  "includes":["/usr/include/stdio.h", "/usr/include/stdlib.h"]}
+///
+/// To reduce the amount of data written to the file, we only record system
+/// headers that are directly included from a file that isn't in the system
+/// directory.
+class HeaderIncludesJSONCallback : public PPCallbacks {
+  SourceManager &SM;
+  raw_ostream *OutputFile;
+  bool OwnsOutputFile;
+  SmallVector<std::string, 16> IncludedHeaders;
+
+public:
+  HeaderIncludesJSONCallback(const Preprocessor *PP, raw_ostream *OutputFile_,
+                             bool OwnsOutputFile_)
+      : SM(PP->getSourceManager()), OutputFile(OutputFile_),
+        OwnsOutputFile(OwnsOutputFile_) {}
+
+  ~HeaderIncludesJSONCallback() override {
+    if (OwnsOutputFile)
+      delete OutputFile;
+  }
+
+  void EndOfMainFile() override;
+
+  void FileChanged(SourceLocation Loc, FileChangeReason Reason,
+                   SrcMgr::CharacteristicKind FileType,
+                   FileID PrevFID) override;
+
+  void FileSkipped(const FileEntryRef &SkippedFile, const Token &FilenameTok,
+                   SrcMgr::CharacteristicKind FileType) override;
+};
 }
 
 static void PrintHeaderInfo(raw_ostream *OutputFile, StringRef Filename,
@@ -116,16 +154,34 @@
     }
   }
 
-  // Print header info for extra headers, pretending they were discovered by
-  // the regular preprocessor. The primary use case is to support proper
-  // generation of Make / Ninja file dependencies for implicit includes, such
-  // as sanitizer ignorelists. It's only important for cl.exe compatibility,
-  // the GNU way to generate rules is -M / -MM / -MD / -MMD.
-  for (const auto &Header : DepOpts.ExtraDeps)
-    PrintHeaderInfo(OutputFile, Header.first, ShowDepth, 2, MSStyle);
-  PP.addPPCallbacks(std::make_unique<HeaderIncludesCallback>(
-      &PP, ShowAllHeaders, OutputFile, DepOpts, OwnsOutputFile, ShowDepth,
-      MSStyle));
+  switch (DepOpts.HeaderIncludeFormat) {
+  case HIF_None:
+    llvm_unreachable("unexpected header format kind");
+  case HIF_Textual: {
+    assert(!DepOpts.HeaderIncludeFiltering &&
+           "header filtering is currently always disabled when output format is"
+           "textual");
+    // Print header info for extra headers, pretending they were discovered by
+    // the regular preprocessor. The primary use case is to support proper
+    // generation of Make / Ninja file dependencies for implicit includes, such
+    // as sanitizer ignorelists. It's only important for cl.exe compatibility,
+    // the GNU way to generate rules is -M / -MM / -MD / -MMD.
+    for (const auto &Header : DepOpts.ExtraDeps)
+      PrintHeaderInfo(OutputFile, Header.first, ShowDepth, 2, MSStyle);
+    PP.addPPCallbacks(std::make_unique<HeaderIncludesCallback>(
+        &PP, ShowAllHeaders, OutputFile, DepOpts, OwnsOutputFile, ShowDepth,
+        MSStyle));
+    break;
+  }
+  case HIF_JSON: {
+    assert(DepOpts.HeaderIncludeFiltering &&
+           "header filtering is currently always enabled when output format is"
+           "json");
+    PP.addPPCallbacks(std::make_unique<HeaderIncludesJSONCallback>(
+        &PP, OutputFile, OwnsOutputFile));
+    break;
+  }
+  }
 }
 
 void HeaderIncludesCallback::FileChanged(SourceLocation Loc,
@@ -197,3 +253,64 @@
   PrintHeaderInfo(OutputFile, SkippedFile.getName(), ShowDepth,
                   CurrentIncludeDepth + 1, MSStyle);
 }
+
+void HeaderIncludesJSONCallback::EndOfMainFile() {
+  const FileEntry *FE = SM.getFileEntryForID(SM.getMainFileID());
+  SmallString<256> MainFile(FE->getName());
+  SM.getFileManager().makeAbsolutePath(MainFile);
+
+  std::string Str;
+  llvm::raw_string_ostream OS(Str);
+  llvm::json::OStream JOS(OS);
+  JOS.object([&] {
+    JOS.attribute("source", MainFile.c_str());
+    JOS.attributeArray("includes", [&] {
+      llvm::StringSet<> SeenHeaders;
+      for (const std::string &H : IncludedHeaders)
+        if (SeenHeaders.insert(H).second)
+          JOS.value(H);
+    });
+  });
+  OS << "\n";
+
+  if (OutputFile->get_kind() == raw_ostream::OStreamKind::OK_FDStream) {
+    llvm::raw_fd_ostream *FDS = static_cast<llvm::raw_fd_ostream *>(OutputFile);
+    if (auto L = FDS->lock())
+      *OutputFile << Str;
+  } else
+    *OutputFile << Str;
+}
+
+/// Determine whether the header file should be recorded. The header file should
+/// be recorded only if the header file is a system header and the current file
+/// isn't a system header.
+static bool shouldRecordNewFile(SrcMgr::CharacteristicKind NewFileType,
+                                SourceLocation PrevLoc, SourceManager &SM) {
+  return SrcMgr::isSystem(NewFileType) && !SM.isInSystemHeader(PrevLoc);
+}
+
+void HeaderIncludesJSONCallback::FileChanged(
+    SourceLocation Loc, FileChangeReason Reason,
+    SrcMgr::CharacteristicKind NewFileType, FileID PrevFID) {
+  if (!shouldRecordNewFile(NewFileType, SM.getLocForStartOfFile(PrevFID), SM))
+    return;
+
+  // Unless we are exiting a #include, make sure to skip ahead to the line the
+  // #include directive was at.
+  PresumedLoc UserLoc = SM.getPresumedLoc(Loc);
+  if (UserLoc.isInvalid())
+    return;
+
+  if (Reason == PPCallbacks::EnterFile &&
+      UserLoc.getFilename() != StringRef("<command line>"))
+    IncludedHeaders.push_back(UserLoc.getFilename());
+}
+
+void HeaderIncludesJSONCallback::FileSkipped(
+    const FileEntryRef &SkippedFile, const Token &FilenameTok,
+    SrcMgr::CharacteristicKind FileType) {
+  if (!shouldRecordNewFile(FileType, FilenameTok.getLocation(), SM))
+    return;
+
+  IncludedHeaders.push_back(SkippedFile.getName().str());
+}
Index: clang/lib/Driver/ToolChains/Clang.cpp
===================================================================
--- clang/lib/Driver/ToolChains/Clang.cpp
+++ clang/lib/Driver/ToolChains/Clang.cpp
@@ -27,6 +27,7 @@
 #include "clang/Basic/CLWarnings.h"
 #include "clang/Basic/CharInfo.h"
 #include "clang/Basic/CodeGenOptions.h"
+#include "clang/Basic/HeaderIncludeFormatKind.h"
 #include "clang/Basic/LangOptions.h"
 #include "clang/Basic/MakeSupport.h"
 #include "clang/Basic/ObjCRuntime.h"
@@ -5645,12 +5646,18 @@
   }
   Args.AddAllArgs(CmdArgs, options::OPT_fshow_skipped_includes);
 
-  if (D.CCPrintHeaders && !D.CCGenDiagnostics) {
+  if (D.CCPrintHeadersFormat && !D.CCGenDiagnostics) {
     CmdArgs.push_back("-header-include-file");
     CmdArgs.push_back(!D.CCPrintHeadersFilename.empty()
                           ? D.CCPrintHeadersFilename.c_str()
                           : "-");
     CmdArgs.push_back("-sys-header-deps");
+    CmdArgs.push_back(Args.MakeArgString(
+        "-header-include-format=" +
+        std::string(headerIncludeFormatKindToString(D.CCPrintHeadersFormat))));
+    CmdArgs.push_back(Args.MakeArgString(
+        "-header-include-filtering=" +
+        std::string(D.CCPrintHeadersFiltering ? "on" : "off")));
   }
   Args.AddLastArg(CmdArgs, options::OPT_P);
   Args.AddLastArg(CmdArgs, options::OPT_print_ivar_layout);
Index: clang/lib/Driver/Driver.cpp
===================================================================
--- clang/lib/Driver/Driver.cpp
+++ clang/lib/Driver/Driver.cpp
@@ -197,10 +197,10 @@
       ModulesModeCXX20(false), LTOMode(LTOK_None),
       ClangExecutable(ClangExecutable), SysRoot(DEFAULT_SYSROOT),
       DriverTitle(Title), CCCPrintBindings(false), CCPrintOptions(false),
-      CCPrintHeaders(false), CCLogDiagnostics(false), CCGenDiagnostics(false),
-      CCPrintProcessStats(false), TargetTriple(TargetTriple), Saver(Alloc),
-      CheckInputsExist(true), ProbePrecompiled(true),
-      SuppressMissingInputWarning(false) {
+      CCPrintHeadersFiltering(false), CCLogDiagnostics(false),
+      CCGenDiagnostics(false), CCPrintProcessStats(false),
+      TargetTriple(TargetTriple), Saver(Alloc), CheckInputsExist(true),
+      ProbePrecompiled(true), SuppressMissingInputWarning(false) {
   // Provide a sane fallback if no VFS is specified.
   if (!this->VFS)
     this->VFS = llvm::vfs::getRealFileSystem();
Index: clang/include/clang/Frontend/DependencyOutputOptions.h
===================================================================
--- clang/include/clang/Frontend/DependencyOutputOptions.h
+++ clang/include/clang/Frontend/DependencyOutputOptions.h
@@ -9,6 +9,7 @@
 #ifndef LLVM_CLANG_FRONTEND_DEPENDENCYOUTPUTOPTIONS_H
 #define LLVM_CLANG_FRONTEND_DEPENDENCYOUTPUTOPTIONS_H
 
+#include "clang/Basic/HeaderIncludeFormatKind.h"
 #include <string>
 #include <vector>
 
@@ -44,6 +45,12 @@
                                           /// due to the "include guard
                                           /// optimization" or #pragma once.
 
+  /// The format of header information.
+  HeaderIncludeFormatKind HeaderIncludeFormat = HIF_Textual;
+
+  /// Determine whether header information should be filtered.
+  bool HeaderIncludeFiltering = false;
+
   /// Destination of cl.exe style /showIncludes info.
   ShowIncludesDestination ShowIncludesDest = ShowIncludesDestination::None;
 
@@ -80,7 +87,7 @@
   DependencyOutputOptions()
       : IncludeSystemHeaders(0), ShowHeaderIncludes(0), UsePhonyTargets(0),
         AddMissingHeaderDeps(0), IncludeModuleFiles(0),
-        ShowSkippedHeaderIncludes(0) {}
+        ShowSkippedHeaderIncludes(0), HeaderIncludeFormat(HIF_Textual) {}
 };
 
 }  // end namespace clang
Index: clang/include/clang/Driver/Options.td
===================================================================
--- clang/include/clang/Driver/Options.td
+++ clang/include/clang/Driver/Options.td
@@ -5656,6 +5656,14 @@
 def header_include_file : Separate<["-"], "header-include-file">,
   HelpText<"Filename (or -) to write header include output to">,
   MarshallingInfoString<DependencyOutputOpts<"HeaderIncludeOutputFile">>;
+def header_include_format_EQ : Joined<["-"], "header-include-format=">,
+  HelpText<"set format in which header info is emitted">,
+  Values<"textual,json">, NormalizedValues<["HIF_Textual", "HIF_JSON"]>,
+  MarshallingInfoEnum<DependencyOutputOpts<"HeaderIncludeFormat">, "HIF_Textual">;
+def header_include_filtering_EQ : Joined<["-"], "header-include-filtering=">,
+  HelpText<"set the flag that enables filtering header information">,
+  Values<"off,on">, NormalizedValues<["false", "true"]>,
+  MarshallingInfoEnum<DependencyOutputOpts<"HeaderIncludeFiltering">, "false">;
 def show_includes : Flag<["--"], "show-includes">,
   HelpText<"Print cl.exe style /showIncludes to stdout">;
 
Index: clang/include/clang/Driver/Driver.h
===================================================================
--- clang/include/clang/Driver/Driver.h
+++ clang/include/clang/Driver/Driver.h
@@ -10,6 +10,7 @@
 #define LLVM_CLANG_DRIVER_DRIVER_H
 
 #include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/HeaderIncludeFormatKind.h"
 #include "clang/Basic/LLVM.h"
 #include "clang/Driver/Action.h"
 #include "clang/Driver/DriverDiagnostic.h"
@@ -233,9 +234,17 @@
   /// CCPrintOptionsFilename or to stderr.
   unsigned CCPrintOptions : 1;
 
-  /// Set CC_PRINT_HEADERS mode, which causes the frontend to log header include
-  /// information to CCPrintHeadersFilename or to stderr.
-  unsigned CCPrintHeaders : 1;
+  /// The format of the header information that is emitted. If CC_PRINT_HEADERS
+  /// is set, the format is textual. Otherwise, the format is determined by the
+  /// enviroment variable CC_PRINT_HEADERS_FORMAT.
+  HeaderIncludeFormatKind CCPrintHeadersFormat = HIF_None;
+
+  /// This flag determines whether clang should filter the header information
+  /// that is emitted. If enviroment variable CC_PRINT_HEADERS_FILTERING is set
+  /// to "off", the header information isn't filtered. If it's set to "on", only
+  /// system headers that are directly included from non-system headers are
+  /// emitted.
+  unsigned CCPrintHeadersFiltering : 1;
 
   /// Set CC_LOG_DIAGNOSTICS mode, which causes the frontend to log diagnostics
   /// to CCLogDiagnosticsFilename or to stderr, in a stable machine readable
Index: clang/include/clang/Basic/HeaderIncludeFormatKind.h
===================================================================
--- /dev/null
+++ clang/include/clang/Basic/HeaderIncludeFormatKind.h
@@ -0,0 +1,53 @@
+//===--- HeaderIncludeFormatKind.h - Header Include Format ------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Defines an enum that represents the format used to emit included headers.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_BASIC_HEADERINCLUDEFORMATKIND_H
+#define LLVM_CLANG_BASIC_HEADERINCLUDEFORMATKIND_H
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/ErrorHandling.h"
+#include <utility>
+
+namespace clang {
+enum HeaderIncludeFormatKind { HIF_None, HIF_Textual, HIF_JSON };
+
+inline HeaderIncludeFormatKind
+stringToHeaderIncludeFormatKind(const char *Str) {
+  return llvm::StringSwitch<HeaderIncludeFormatKind>(Str)
+      .Case("textual", HIF_Textual)
+      .Case("json", HIF_JSON)
+      .Default(HIF_None);
+}
+
+inline bool stringToHeaderIncludeFiltering(const char *Str, unsigned &Var) {
+  std::pair<bool, bool> P = llvm::StringSwitch<std::pair<bool, bool>>(Str)
+                                .Case("off", {true, false})
+                                .Case("on", {true, true})
+                                .Default({false, false});
+  Var = P.second;
+  return P.first;
+}
+
+inline const char *headerIncludeFormatKindToString(HeaderIncludeFormatKind K) {
+  switch (K) {
+  case HIF_None:
+    llvm_unreachable("unexpected format kind");
+  case HIF_Textual:
+    return "textual";
+  case HIF_JSON:
+    return "json";
+  }
+}
+
+} // end namespace clang
+
+#endif // LLVM_CLANG_BASIC_HEADERINCLUDEFORMATKIND_H
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to