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 
18 namespace clang {
19 
20 inline 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 
27 inline 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 
81 inline 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