JsonSupport.h 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. #pragma once
  2. #ifdef __GNUC__
  3. #pragma GCC diagnostic push
  4. #pragma GCC diagnostic ignored "-Wunused-parameter"
  5. #endif
  6. //===- JsonSupport.h - JSON Output Utilities --------------------*- C++ -*-===//
  7. //
  8. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  9. // See https://llvm.org/LICENSE.txt for license information.
  10. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  11. //
  12. //===----------------------------------------------------------------------===//
  13. #ifndef LLVM_CLANG_BASIC_JSONSUPPORT_H
  14. #define LLVM_CLANG_BASIC_JSONSUPPORT_H
  15. #include "clang/Basic/LLVM.h"
  16. #include "clang/Basic/SourceManager.h"
  17. #include "llvm/ADT/StringRef.h"
  18. #include "llvm/Support/Path.h"
  19. #include "llvm/Support/raw_ostream.h"
  20. #include <iterator>
  21. namespace clang {
  22. inline raw_ostream &Indent(raw_ostream &Out, const unsigned int Space,
  23. bool IsDot) {
  24. for (unsigned int I = 0; I < Space * 2; ++I)
  25. Out << (IsDot ? "&nbsp;" : " ");
  26. return Out;
  27. }
  28. inline std::string JsonFormat(StringRef RawSR, bool AddQuotes) {
  29. if (RawSR.empty())
  30. return "null";
  31. // Trim special characters.
  32. std::string Str = RawSR.trim().str();
  33. size_t Pos = 0;
  34. // Escape backslashes.
  35. while (true) {
  36. Pos = Str.find('\\', Pos);
  37. if (Pos == std::string::npos)
  38. break;
  39. // Prevent bad conversions.
  40. size_t TempPos = (Pos != 0) ? Pos - 1 : 0;
  41. // See whether the current backslash is not escaped.
  42. if (TempPos != Str.find("\\\\", Pos)) {
  43. Str.insert(Pos, "\\");
  44. ++Pos; // As we insert the backslash move plus one.
  45. }
  46. ++Pos;
  47. }
  48. // Escape double quotes.
  49. Pos = 0;
  50. while (true) {
  51. Pos = Str.find('\"', Pos);
  52. if (Pos == std::string::npos)
  53. break;
  54. // Prevent bad conversions.
  55. size_t TempPos = (Pos != 0) ? Pos - 1 : 0;
  56. // See whether the current double quote is not escaped.
  57. if (TempPos != Str.find("\\\"", Pos)) {
  58. Str.insert(Pos, "\\");
  59. ++Pos; // As we insert the escape-character move plus one.
  60. }
  61. ++Pos;
  62. }
  63. // Remove new-lines.
  64. llvm::erase_value(Str, '\n');
  65. if (!AddQuotes)
  66. return Str;
  67. return '\"' + Str + '\"';
  68. }
  69. inline void printSourceLocationAsJson(raw_ostream &Out, SourceLocation Loc,
  70. const SourceManager &SM,
  71. bool AddBraces = true) {
  72. // Mostly copy-pasted from SourceLocation::print.
  73. if (!Loc.isValid()) {
  74. Out << "null";
  75. return;
  76. }
  77. if (Loc.isFileID()) {
  78. PresumedLoc PLoc = SM.getPresumedLoc(Loc);
  79. if (PLoc.isInvalid()) {
  80. Out << "null";
  81. return;
  82. }
  83. // The macro expansion and spelling pos is identical for file locs.
  84. if (AddBraces)
  85. Out << "{ ";
  86. std::string filename(PLoc.getFilename());
  87. if (is_style_windows(llvm::sys::path::Style::native)) {
  88. // Remove forbidden Windows path characters
  89. auto RemoveIt =
  90. std::remove_if(filename.begin(), filename.end(), [](auto Char) {
  91. static const char ForbiddenChars[] = "<>*?\"|";
  92. return std::find(std::begin(ForbiddenChars),
  93. std::end(ForbiddenChars),
  94. Char) != std::end(ForbiddenChars);
  95. });
  96. filename.erase(RemoveIt, filename.end());
  97. // Handle windows-specific path delimiters.
  98. std::replace(filename.begin(), filename.end(), '\\', '/');
  99. }
  100. Out << "\"line\": " << PLoc.getLine()
  101. << ", \"column\": " << PLoc.getColumn()
  102. << ", \"file\": \"" << filename << "\"";
  103. if (AddBraces)
  104. Out << " }";
  105. return;
  106. }
  107. // We want 'location: { ..., spelling: { ... }}' but not
  108. // 'location: { ... }, spelling: { ... }', hence the dance
  109. // with braces.
  110. Out << "{ ";
  111. printSourceLocationAsJson(Out, SM.getExpansionLoc(Loc), SM, false);
  112. Out << ", \"spelling\": ";
  113. printSourceLocationAsJson(Out, SM.getSpellingLoc(Loc), SM, true);
  114. Out << " }";
  115. }
  116. } // namespace clang
  117. #endif // LLVM_CLANG_BASIC_JSONSUPPORT_H
  118. #ifdef __GNUC__
  119. #pragma GCC diagnostic pop
  120. #endif