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(Val: FID); |
30 | if (I != FIDs.end()) |
31 | return I->second; |
32 | unsigned NewValue = V.size(); |
33 | FIDs[FID] = NewValue; |
34 | V.push_back(Elt: 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(SpellingLoc: SM.getExpansionLoc(Loc: 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(Val: 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(SpellingLoc: SM.getExpansionLoc(Loc: 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 &(raw_ostream &o) { |
63 | static const char * = |
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 (char c : s) { |
81 | switch (c) { |
82 | default: |
83 | o << c; |
84 | break; |
85 | case '&': |
86 | o << "&" ; |
87 | break; |
88 | case '<': |
89 | o << "<" ; |
90 | break; |
91 | case '>': |
92 | o << ">" ; |
93 | break; |
94 | case '\'': |
95 | o << "'" ; |
96 | break; |
97 | case '\"': |
98 | o << """ ; |
99 | break; |
100 | } |
101 | } |
102 | o << "</string>" ; |
103 | return o; |
104 | } |
105 | |
106 | inline void EmitLocation(raw_ostream &o, const SourceManager &SM, |
107 | SourceLocation L, const FIDMap &FM, unsigned indent) { |
108 | if (L.isInvalid()) return; |
109 | |
110 | FullSourceLoc Loc(SM.getExpansionLoc(Loc: L), const_cast<SourceManager &>(SM)); |
111 | |
112 | Indent(o, indent) << "<dict>\n" ; |
113 | Indent(o, indent) << " <key>line</key>" ; |
114 | EmitInteger(o, value: Loc.getExpansionLineNumber()) << '\n'; |
115 | Indent(o, indent) << " <key>col</key>" ; |
116 | EmitInteger(o, value: Loc.getExpansionColumnNumber()) << '\n'; |
117 | Indent(o, indent) << " <key>file</key>" ; |
118 | EmitInteger(o, value: GetFID(FIDs: FM, SM, L: Loc)) << '\n'; |
119 | Indent(o, indent) << "</dict>\n" ; |
120 | } |
121 | |
122 | inline void EmitRange(raw_ostream &o, const SourceManager &SM, |
123 | CharSourceRange R, const FIDMap &FM, unsigned indent) { |
124 | if (R.isInvalid()) return; |
125 | |
126 | assert(R.isCharRange() && "cannot handle a token range" ); |
127 | Indent(o, indent) << "<array>\n" ; |
128 | EmitLocation(o, SM, L: R.getBegin(), FM, indent: indent + 1); |
129 | |
130 | // The ".getLocWithOffset(-1)" emulates the behavior of an off-by-one bug |
131 | // in Lexer that is already fixed. It is here for backwards compatibility |
132 | // even though it is incorrect. |
133 | EmitLocation(o, SM, L: R.getEnd().getLocWithOffset(Offset: -1), FM, indent: indent + 1); |
134 | Indent(o, indent) << "</array>\n" ; |
135 | } |
136 | |
137 | } // namespace markup |
138 | } // namespace clang |
139 | |
140 | #endif // LLVM_CLANG_BASIC_PLISTSUPPORT_H |
141 | |