1 //===- PlistSupport.h - Plist 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_PLISTSUPPORT_H 10 #define LLVM_CLANG_BASIC_PLISTSUPPORT_H 11 12 #include "clang/Basic/LLVM.h" 13 #include "clang/Basic/SourceLocation.h" 14 #include "clang/Basic/SourceManager.h" 15 #include "llvm/ADT/DenseMap.h" 16 #include "llvm/ADT/SmallVector.h" 17 #include "llvm/ADT/StringRef.h" 18 #include "llvm/Support/raw_ostream.h" 19 #include <cassert> 20 #include <cstdint> 21 22 namespace clang { 23 namespace markup { 24 25 using FIDMap = llvm::DenseMap<FileID, unsigned>; 26 27 inline unsigned AddFID(FIDMap &FIDs, SmallVectorImpl<FileID> &V, 28 FileID FID) { 29 FIDMap::iterator I = FIDs.find(FID); 30 if (I != FIDs.end()) 31 return I->second; 32 unsigned NewValue = V.size(); 33 FIDs[FID] = NewValue; 34 V.push_back(FID); 35 return NewValue; 36 } 37 38 inline unsigned AddFID(FIDMap &FIDs, SmallVectorImpl<FileID> &V, 39 const SourceManager &SM, SourceLocation L) { 40 FileID FID = SM.getFileID(SM.getExpansionLoc(L)); 41 return AddFID(FIDs, V, FID); 42 } 43 44 inline unsigned GetFID(const FIDMap &FIDs, FileID FID) { 45 FIDMap::const_iterator I = FIDs.find(FID); 46 assert(I != FIDs.end()); 47 return I->second; 48 } 49 50 inline unsigned GetFID(const FIDMap &FIDs, const SourceManager &SM, 51 SourceLocation L) { 52 FileID FID = SM.getFileID(SM.getExpansionLoc(L)); 53 return GetFID(FIDs, FID); 54 } 55 56 inline raw_ostream &Indent(raw_ostream &o, const unsigned indent) { 57 for (unsigned i = 0; i < indent; ++i) 58 o << ' '; 59 return o; 60 } 61 62 inline raw_ostream &EmitPlistHeader(raw_ostream &o) { 63 static const char *PlistHeader = 64 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" 65 "<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" " 66 "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" 67 "<plist version=\"1.0\">\n"; 68 return o << PlistHeader; 69 } 70 71 inline raw_ostream &EmitInteger(raw_ostream &o, int64_t value) { 72 o << "<integer>"; 73 o << value; 74 o << "</integer>"; 75 return o; 76 } 77 78 inline raw_ostream &EmitString(raw_ostream &o, StringRef s) { 79 o << "<string>"; 80 for (StringRef::const_iterator I = s.begin(), E = s.end(); I != E; ++I) { 81 char c = *I; 82 switch (c) { 83 default: 84 o << c; 85 break; 86 case '&': 87 o << "&"; 88 break; 89 case '<': 90 o << "<"; 91 break; 92 case '>': 93 o << ">"; 94 break; 95 case '\'': 96 o << "'"; 97 break; 98 case '\"': 99 o << """; 100 break; 101 } 102 } 103 o << "</string>"; 104 return o; 105 } 106 107 inline void EmitLocation(raw_ostream &o, const SourceManager &SM, 108 SourceLocation L, const FIDMap &FM, unsigned indent) { 109 if (L.isInvalid()) return; 110 111 FullSourceLoc Loc(SM.getExpansionLoc(L), const_cast<SourceManager &>(SM)); 112 113 Indent(o, indent) << "<dict>\n"; 114 Indent(o, indent) << " <key>line</key>"; 115 EmitInteger(o, Loc.getExpansionLineNumber()) << '\n'; 116 Indent(o, indent) << " <key>col</key>"; 117 EmitInteger(o, Loc.getExpansionColumnNumber()) << '\n'; 118 Indent(o, indent) << " <key>file</key>"; 119 EmitInteger(o, GetFID(FM, SM, Loc)) << '\n'; 120 Indent(o, indent) << "</dict>\n"; 121 } 122 123 inline void EmitRange(raw_ostream &o, const SourceManager &SM, 124 CharSourceRange R, const FIDMap &FM, unsigned indent) { 125 if (R.isInvalid()) return; 126 127 assert(R.isCharRange() && "cannot handle a token range"); 128 Indent(o, indent) << "<array>\n"; 129 EmitLocation(o, SM, R.getBegin(), FM, indent + 1); 130 131 // The ".getLocWithOffset(-1)" emulates the behavior of an off-by-one bug 132 // in Lexer that is already fixed. It is here for backwards compatibility 133 // even though it is incorrect. 134 EmitLocation(o, SM, R.getEnd().getLocWithOffset(-1), FM, indent + 1); 135 Indent(o, indent) << "</array>\n"; 136 } 137 138 } // namespace markup 139 } // namespace clang 140 141 #endif // LLVM_CLANG_BASIC_PLISTSUPPORT_H 142