//===- JsonSupport.h - JSON Output Utilities --------------------*- 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 // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_BASIC_JSONSUPPORT_H #define LLVM_CLANG_BASIC_JSONSUPPORT_H #include "clang/Basic/LLVM.h" #include "clang/Basic/SourceManager.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" #include namespace clang { inline raw_ostream &Indent(raw_ostream &Out, const unsigned int Space, bool IsDot) { for (unsigned int I = 0; I < Space * 2; ++I) Out << (IsDot ? " " : " "); return Out; } inline std::string JsonFormat(StringRef RawSR, bool AddQuotes) { if (RawSR.empty()) return "null"; // Trim special characters. std::string Str = RawSR.trim().str(); size_t Pos = 0; // Escape backslashes. while (true) { Pos = Str.find('\\', Pos); if (Pos == std::string::npos) break; // Prevent bad conversions. size_t TempPos = (Pos != 0) ? Pos - 1 : 0; // See whether the current backslash is not escaped. if (TempPos != Str.find("\\\\", Pos)) { Str.insert(Pos, "\\"); ++Pos; // As we insert the backslash move plus one. } ++Pos; } // Escape double quotes. Pos = 0; while (true) { Pos = Str.find('\"', Pos); if (Pos == std::string::npos) break; // Prevent bad conversions. size_t TempPos = (Pos != 0) ? Pos - 1 : 0; // See whether the current double quote is not escaped. if (TempPos != Str.find("\\\"", Pos)) { Str.insert(Pos, "\\"); ++Pos; // As we insert the escape-character move plus one. } ++Pos; } // Remove new-lines. llvm::erase_value(Str, '\n'); if (!AddQuotes) return Str; return '\"' + Str + '\"'; } inline void printSourceLocationAsJson(raw_ostream &Out, SourceLocation Loc, const SourceManager &SM, bool AddBraces = true) { // Mostly copy-pasted from SourceLocation::print. if (!Loc.isValid()) { Out << "null"; return; } if (Loc.isFileID()) { PresumedLoc PLoc = SM.getPresumedLoc(Loc); if (PLoc.isInvalid()) { Out << "null"; return; } // The macro expansion and spelling pos is identical for file locs. if (AddBraces) Out << "{ "; std::string filename(PLoc.getFilename()); if (is_style_windows(llvm::sys::path::Style::native)) { // Remove forbidden Windows path characters llvm::erase_if(filename, [](auto Char) { static const char ForbiddenChars[] = "<>*?\"|"; return llvm::is_contained(ForbiddenChars, Char); }); // Handle windows-specific path delimiters. std::replace(filename.begin(), filename.end(), '\\', '/'); } Out << "\"line\": " << PLoc.getLine() << ", \"column\": " << PLoc.getColumn() << ", \"file\": \"" << filename << "\""; if (AddBraces) Out << " }"; return; } // We want 'location: { ..., spelling: { ... }}' but not // 'location: { ... }, spelling: { ... }', hence the dance // with braces. Out << "{ "; printSourceLocationAsJson(Out, SM.getExpansionLoc(Loc), SM, false); Out << ", \"spelling\": "; printSourceLocationAsJson(Out, SM.getSpellingLoc(Loc), SM, true); Out << " }"; } } // namespace clang #endif // LLVM_CLANG_BASIC_JSONSUPPORT_H