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 22namespace clang { 23namespace markup { 24 25using FIDMap = llvm::DenseMap<FileID, unsigned>; 26 27inline 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 38inline 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 44inline 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 50inline 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 56inline raw_ostream &Indent(raw_ostream &o, const unsigned indent) { 57 for (unsigned i = 0; i < indent; ++i) 58 o << ' '; 59 return o; 60} 61 62inline 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 71inline raw_ostream &EmitInteger(raw_ostream &o, int64_t value) { 72 o << "<integer>"; 73 o << value; 74 o << "</integer>"; 75 return o; 76} 77 78inline 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 107inline 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 123inline 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