1351280Sdim//===- JsonSupport.h - JSON Output Utilities --------------------*- C++ -*-===//
2351280Sdim//
3351280Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4351280Sdim// See https://llvm.org/LICENSE.txt for license information.
5351280Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6351280Sdim//
7351280Sdim//===----------------------------------------------------------------------===//
8351280Sdim
9351280Sdim#ifndef LLVM_CLANG_BASIC_JSONSUPPORT_H
10351280Sdim#define LLVM_CLANG_BASIC_JSONSUPPORT_H
11351280Sdim
12351280Sdim#include "clang/Basic/LLVM.h"
13351280Sdim#include "clang/Basic/SourceManager.h"
14351280Sdim#include "llvm/ADT/StringRef.h"
15351280Sdim#include "llvm/Support/raw_ostream.h"
16351280Sdim
17351280Sdim
18351280Sdimnamespace clang {
19351280Sdim
20351280Sdiminline raw_ostream &Indent(raw_ostream &Out, const unsigned int Space,
21351280Sdim                           bool IsDot) {
22351280Sdim  for (unsigned int I = 0; I < Space * 2; ++I)
23351280Sdim    Out << (IsDot ? "&nbsp;" : " ");
24351280Sdim  return Out;
25351280Sdim}
26351280Sdim
27351280Sdiminline std::string JsonFormat(StringRef RawSR, bool AddQuotes) {
28351280Sdim  if (RawSR.empty())
29351280Sdim    return "null";
30351280Sdim
31351280Sdim  // Trim special characters.
32351280Sdim  std::string Str = RawSR.trim().str();
33351280Sdim  size_t Pos = 0;
34351280Sdim
35351280Sdim  // Escape backslashes.
36351280Sdim  while (true) {
37351280Sdim    Pos = Str.find('\\', Pos);
38351280Sdim    if (Pos == std::string::npos)
39351280Sdim      break;
40351280Sdim
41351280Sdim    // Prevent bad conversions.
42351280Sdim    size_t TempPos = (Pos != 0) ? Pos - 1 : 0;
43351280Sdim
44351280Sdim    // See whether the current backslash is not escaped.
45351280Sdim    if (TempPos != Str.find("\\\\", Pos)) {
46351280Sdim      Str.insert(Pos, "\\");
47351280Sdim      ++Pos; // As we insert the backslash move plus one.
48351280Sdim    }
49351280Sdim
50351280Sdim    ++Pos;
51351280Sdim  }
52351280Sdim
53351280Sdim  // Escape double quotes.
54351280Sdim  Pos = 0;
55351280Sdim  while (true) {
56351280Sdim    Pos = Str.find('\"', Pos);
57351280Sdim    if (Pos == std::string::npos)
58351280Sdim      break;
59351280Sdim
60351280Sdim    // Prevent bad conversions.
61351280Sdim    size_t TempPos = (Pos != 0) ? Pos - 1 : 0;
62351280Sdim
63351280Sdim    // See whether the current double quote is not escaped.
64351280Sdim    if (TempPos != Str.find("\\\"", Pos)) {
65351280Sdim      Str.insert(Pos, "\\");
66351280Sdim      ++Pos; // As we insert the escape-character move plus one.
67351280Sdim    }
68351280Sdim
69351280Sdim    ++Pos;
70351280Sdim  }
71351280Sdim
72351280Sdim  // Remove new-lines.
73351280Sdim  Str.erase(std::remove(Str.begin(), Str.end(), '\n'), Str.end());
74351280Sdim
75351280Sdim  if (!AddQuotes)
76351280Sdim    return Str;
77351280Sdim
78351280Sdim  return '\"' + Str + '\"';
79351280Sdim}
80351280Sdim
81351280Sdiminline void printSourceLocationAsJson(raw_ostream &Out, SourceLocation Loc,
82351280Sdim                                      const SourceManager &SM,
83351280Sdim                                      bool AddBraces = true) {
84351280Sdim  // Mostly copy-pasted from SourceLocation::print.
85351280Sdim  if (!Loc.isValid()) {
86351280Sdim    Out << "null";
87351280Sdim    return;
88351280Sdim  }
89351280Sdim
90351280Sdim  if (Loc.isFileID()) {
91351280Sdim    PresumedLoc PLoc = SM.getPresumedLoc(Loc);
92351280Sdim
93351280Sdim    if (PLoc.isInvalid()) {
94351280Sdim      Out << "null";
95351280Sdim      return;
96351280Sdim    }
97351280Sdim    // The macro expansion and spelling pos is identical for file locs.
98351280Sdim    if (AddBraces)
99351280Sdim      Out << "{ ";
100351280Sdim    Out << "\"line\": " << PLoc.getLine()
101351280Sdim        << ", \"column\": " << PLoc.getColumn()
102351280Sdim        << ", \"file\": \"" << PLoc.getFilename() << "\"";
103351280Sdim    if (AddBraces)
104351280Sdim      Out << " }";
105351280Sdim    return;
106351280Sdim  }
107351280Sdim
108351280Sdim  // We want 'location: { ..., spelling: { ... }}' but not
109351280Sdim  // 'location: { ... }, spelling: { ... }', hence the dance
110351280Sdim  // with braces.
111351280Sdim  Out << "{ ";
112351280Sdim  printSourceLocationAsJson(Out, SM.getExpansionLoc(Loc), SM, false);
113351280Sdim  Out << ", \"spelling\": ";
114351280Sdim  printSourceLocationAsJson(Out, SM.getSpellingLoc(Loc), SM, true);
115351280Sdim  Out << " }";
116351280Sdim}
117351280Sdim} // namespace clang
118351280Sdim
119351280Sdim#endif // LLVM_CLANG_BASIC_JSONSUPPORT_H
120