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