]>
Commit | Line | Data |
---|---|---|
223e47cc LB |
1 | //===- SourceMgr.h - Manager for Source Buffers & Diagnostics ---*- C++ -*-===// |
2 | // | |
3 | // The LLVM Compiler Infrastructure | |
4 | // | |
5 | // This file is distributed under the University of Illinois Open Source | |
6 | // License. See LICENSE.TXT for details. | |
7 | // | |
8 | //===----------------------------------------------------------------------===// | |
9 | // | |
10 | // This file declares the SMDiagnostic and SourceMgr classes. This | |
11 | // provides a simple substrate for diagnostics, #include handling, and other low | |
12 | // level things for simple parsers. | |
13 | // | |
14 | //===----------------------------------------------------------------------===// | |
15 | ||
970d7e83 LB |
16 | #ifndef LLVM_SUPPORT_SOURCEMGR_H |
17 | #define LLVM_SUPPORT_SOURCEMGR_H | |
223e47cc | 18 | |
223e47cc | 19 | #include "llvm/ADT/ArrayRef.h" |
970d7e83 LB |
20 | #include "llvm/ADT/StringRef.h" |
21 | #include "llvm/ADT/Twine.h" | |
1a4d82fc | 22 | #include "llvm/Support/MemoryBuffer.h" |
970d7e83 | 23 | #include "llvm/Support/SMLoc.h" |
223e47cc LB |
24 | #include <string> |
25 | ||
26 | namespace llvm { | |
223e47cc LB |
27 | class SourceMgr; |
28 | class SMDiagnostic; | |
970d7e83 | 29 | class SMFixIt; |
223e47cc LB |
30 | class Twine; |
31 | class raw_ostream; | |
32 | ||
1a4d82fc | 33 | /// This owns the files read by a parser, handles include stacks, |
223e47cc LB |
34 | /// and handles diagnostic wrangling. |
35 | class SourceMgr { | |
36 | public: | |
37 | enum DiagKind { | |
38 | DK_Error, | |
39 | DK_Warning, | |
40 | DK_Note | |
41 | }; | |
1a4d82fc JJ |
42 | |
43 | /// Clients that want to handle their own diagnostics in a custom way can | |
44 | /// register a function pointer+context as a diagnostic handler. | |
45 | /// It gets called each time PrintMessage is invoked. | |
223e47cc LB |
46 | typedef void (*DiagHandlerTy)(const SMDiagnostic &, void *Context); |
47 | private: | |
48 | struct SrcBuffer { | |
1a4d82fc JJ |
49 | /// The memory buffer for the file. |
50 | std::unique_ptr<MemoryBuffer> Buffer; | |
223e47cc | 51 | |
1a4d82fc | 52 | /// This is the location of the parent include, or null if at the top level. |
223e47cc | 53 | SMLoc IncludeLoc; |
1a4d82fc JJ |
54 | |
55 | SrcBuffer() {} | |
56 | ||
57 | SrcBuffer(SrcBuffer &&O) | |
58 | : Buffer(std::move(O.Buffer)), IncludeLoc(O.IncludeLoc) {} | |
223e47cc LB |
59 | }; |
60 | ||
1a4d82fc | 61 | /// This is all of the buffers that we are reading from. |
223e47cc LB |
62 | std::vector<SrcBuffer> Buffers; |
63 | ||
1a4d82fc | 64 | // This is the list of directories we should search for include files in. |
223e47cc LB |
65 | std::vector<std::string> IncludeDirectories; |
66 | ||
1a4d82fc JJ |
67 | /// This is a cache for line number queries, its implementation is really |
68 | /// private to SourceMgr.cpp. | |
223e47cc LB |
69 | mutable void *LineNoCache; |
70 | ||
71 | DiagHandlerTy DiagHandler; | |
72 | void *DiagContext; | |
73 | ||
1a4d82fc JJ |
74 | bool isValidBufferID(unsigned i) const { return i && i <= Buffers.size(); } |
75 | ||
223e47cc LB |
76 | SourceMgr(const SourceMgr&) LLVM_DELETED_FUNCTION; |
77 | void operator=(const SourceMgr&) LLVM_DELETED_FUNCTION; | |
78 | public: | |
1a4d82fc JJ |
79 | SourceMgr() |
80 | : LineNoCache(nullptr), DiagHandler(nullptr), DiagContext(nullptr) {} | |
223e47cc LB |
81 | ~SourceMgr(); |
82 | ||
83 | void setIncludeDirs(const std::vector<std::string> &Dirs) { | |
84 | IncludeDirectories = Dirs; | |
85 | } | |
86 | ||
1a4d82fc JJ |
87 | /// Specify a diagnostic handler to be invoked every time PrintMessage is |
88 | /// called. \p Ctx is passed into the handler when it is invoked. | |
89 | void setDiagHandler(DiagHandlerTy DH, void *Ctx = nullptr) { | |
223e47cc LB |
90 | DiagHandler = DH; |
91 | DiagContext = Ctx; | |
92 | } | |
93 | ||
94 | DiagHandlerTy getDiagHandler() const { return DiagHandler; } | |
95 | void *getDiagContext() const { return DiagContext; } | |
96 | ||
97 | const SrcBuffer &getBufferInfo(unsigned i) const { | |
1a4d82fc JJ |
98 | assert(isValidBufferID(i)); |
99 | return Buffers[i - 1]; | |
223e47cc LB |
100 | } |
101 | ||
102 | const MemoryBuffer *getMemoryBuffer(unsigned i) const { | |
1a4d82fc JJ |
103 | assert(isValidBufferID(i)); |
104 | return Buffers[i - 1].Buffer.get(); | |
223e47cc LB |
105 | } |
106 | ||
970d7e83 LB |
107 | unsigned getNumBuffers() const { |
108 | return Buffers.size(); | |
109 | } | |
110 | ||
1a4d82fc JJ |
111 | unsigned getMainFileID() const { |
112 | assert(getNumBuffers()); | |
113 | return 1; | |
114 | } | |
115 | ||
223e47cc | 116 | SMLoc getParentIncludeLoc(unsigned i) const { |
1a4d82fc JJ |
117 | assert(isValidBufferID(i)); |
118 | return Buffers[i - 1].IncludeLoc; | |
223e47cc LB |
119 | } |
120 | ||
1a4d82fc JJ |
121 | /// Add a new source buffer to this source manager. This takes ownership of |
122 | /// the memory buffer. | |
123 | unsigned AddNewSourceBuffer(std::unique_ptr<MemoryBuffer> F, | |
124 | SMLoc IncludeLoc) { | |
223e47cc | 125 | SrcBuffer NB; |
1a4d82fc | 126 | NB.Buffer = std::move(F); |
223e47cc | 127 | NB.IncludeLoc = IncludeLoc; |
1a4d82fc JJ |
128 | Buffers.push_back(std::move(NB)); |
129 | return Buffers.size(); | |
223e47cc LB |
130 | } |
131 | ||
1a4d82fc JJ |
132 | /// Search for a file with the specified name in the current directory or in |
133 | /// one of the IncludeDirs. | |
134 | /// | |
135 | /// If no file is found, this returns 0, otherwise it returns the buffer ID | |
136 | /// of the stacked file. The full path to the included file can be found in | |
137 | /// \p IncludedFile. | |
223e47cc LB |
138 | unsigned AddIncludeFile(const std::string &Filename, SMLoc IncludeLoc, |
139 | std::string &IncludedFile); | |
140 | ||
1a4d82fc JJ |
141 | /// Return the ID of the buffer containing the specified location. |
142 | /// | |
143 | /// 0 is returned if the buffer is not found. | |
144 | unsigned FindBufferContainingLoc(SMLoc Loc) const; | |
223e47cc | 145 | |
1a4d82fc JJ |
146 | /// Find the line number for the specified location in the specified file. |
147 | /// This is not a fast method. | |
148 | unsigned FindLineNumber(SMLoc Loc, unsigned BufferID = 0) const { | |
223e47cc LB |
149 | return getLineAndColumn(Loc, BufferID).first; |
150 | } | |
151 | ||
1a4d82fc JJ |
152 | /// Find the line and column number for the specified location in the |
153 | /// specified file. This is not a fast method. | |
154 | std::pair<unsigned, unsigned> getLineAndColumn(SMLoc Loc, | |
155 | unsigned BufferID = 0) const; | |
223e47cc | 156 | |
1a4d82fc | 157 | /// Emit a message about the specified location with the specified string. |
223e47cc | 158 | /// |
1a4d82fc | 159 | /// \param ShowColors Display colored messages if output is a terminal and |
223e47cc | 160 | /// the default error handler is used. |
1a4d82fc JJ |
161 | void PrintMessage(raw_ostream &OS, SMLoc Loc, DiagKind Kind, |
162 | const Twine &Msg, | |
163 | ArrayRef<SMRange> Ranges = None, | |
164 | ArrayRef<SMFixIt> FixIts = None, | |
165 | bool ShowColors = true) const; | |
166 | ||
167 | /// Emits a diagnostic to llvm::errs(). | |
223e47cc | 168 | void PrintMessage(SMLoc Loc, DiagKind Kind, const Twine &Msg, |
1a4d82fc JJ |
169 | ArrayRef<SMRange> Ranges = None, |
170 | ArrayRef<SMFixIt> FixIts = None, | |
223e47cc LB |
171 | bool ShowColors = true) const; |
172 | ||
1a4d82fc JJ |
173 | /// Emits a manually-constructed diagnostic to the given output stream. |
174 | /// | |
175 | /// \param ShowColors Display colored messages if output is a terminal and | |
176 | /// the default error handler is used. | |
177 | void PrintMessage(raw_ostream &OS, const SMDiagnostic &Diagnostic, | |
178 | bool ShowColors = true) const; | |
223e47cc | 179 | |
1a4d82fc JJ |
180 | /// Return an SMDiagnostic at the specified location with the specified |
181 | /// string. | |
223e47cc | 182 | /// |
1a4d82fc | 183 | /// \param Msg If non-null, the kind of message (e.g., "error") which is |
223e47cc | 184 | /// prefixed to the message. |
1a4d82fc JJ |
185 | SMDiagnostic GetMessage(SMLoc Loc, DiagKind Kind, const Twine &Msg, |
186 | ArrayRef<SMRange> Ranges = None, | |
187 | ArrayRef<SMFixIt> FixIts = None) const; | |
223e47cc | 188 | |
1a4d82fc JJ |
189 | /// Prints the names of included files and the line of the file they were |
190 | /// included from. A diagnostic handler can use this before printing its | |
191 | /// custom formatted message. | |
223e47cc | 192 | /// |
1a4d82fc JJ |
193 | /// \param IncludeLoc The location of the include. |
194 | /// \param OS the raw_ostream to print on. | |
223e47cc LB |
195 | void PrintIncludeStack(SMLoc IncludeLoc, raw_ostream &OS) const; |
196 | }; | |
197 | ||
198 | ||
970d7e83 LB |
199 | /// Represents a single fixit, a replacement of one range of text with another. |
200 | class SMFixIt { | |
201 | SMRange Range; | |
202 | ||
203 | std::string Text; | |
204 | ||
205 | public: | |
206 | // FIXME: Twine.str() is not very efficient. | |
207 | SMFixIt(SMLoc Loc, const Twine &Insertion) | |
208 | : Range(Loc, Loc), Text(Insertion.str()) { | |
209 | assert(Loc.isValid()); | |
210 | } | |
211 | ||
212 | // FIXME: Twine.str() is not very efficient. | |
213 | SMFixIt(SMRange R, const Twine &Replacement) | |
214 | : Range(R), Text(Replacement.str()) { | |
215 | assert(R.isValid()); | |
216 | } | |
217 | ||
218 | StringRef getText() const { return Text; } | |
219 | SMRange getRange() const { return Range; } | |
220 | ||
221 | bool operator<(const SMFixIt &Other) const { | |
222 | if (Range.Start.getPointer() != Other.Range.Start.getPointer()) | |
223 | return Range.Start.getPointer() < Other.Range.Start.getPointer(); | |
224 | if (Range.End.getPointer() != Other.Range.End.getPointer()) | |
225 | return Range.End.getPointer() < Other.Range.End.getPointer(); | |
226 | return Text < Other.Text; | |
227 | } | |
228 | }; | |
229 | ||
230 | ||
1a4d82fc JJ |
231 | /// Instances of this class encapsulate one diagnostic report, allowing |
232 | /// printing to a raw_ostream as a caret diagnostic. | |
223e47cc LB |
233 | class SMDiagnostic { |
234 | const SourceMgr *SM; | |
235 | SMLoc Loc; | |
236 | std::string Filename; | |
237 | int LineNo, ColumnNo; | |
238 | SourceMgr::DiagKind Kind; | |
239 | std::string Message, LineContents; | |
240 | std::vector<std::pair<unsigned, unsigned> > Ranges; | |
970d7e83 | 241 | SmallVector<SMFixIt, 4> FixIts; |
223e47cc LB |
242 | |
243 | public: | |
244 | // Null diagnostic. | |
245 | SMDiagnostic() | |
1a4d82fc | 246 | : SM(nullptr), LineNo(0), ColumnNo(0), Kind(SourceMgr::DK_Error) {} |
223e47cc | 247 | // Diagnostic with no location (e.g. file not found, command line arg error). |
970d7e83 | 248 | SMDiagnostic(StringRef filename, SourceMgr::DiagKind Knd, StringRef Msg) |
1a4d82fc | 249 | : SM(nullptr), Filename(filename), LineNo(-1), ColumnNo(-1), Kind(Knd), |
223e47cc | 250 | Message(Msg) {} |
1a4d82fc | 251 | |
223e47cc | 252 | // Diagnostic with a location. |
970d7e83 | 253 | SMDiagnostic(const SourceMgr &sm, SMLoc L, StringRef FN, |
223e47cc | 254 | int Line, int Col, SourceMgr::DiagKind Kind, |
970d7e83 LB |
255 | StringRef Msg, StringRef LineStr, |
256 | ArrayRef<std::pair<unsigned,unsigned> > Ranges, | |
1a4d82fc | 257 | ArrayRef<SMFixIt> FixIts = None); |
223e47cc LB |
258 | |
259 | const SourceMgr *getSourceMgr() const { return SM; } | |
260 | SMLoc getLoc() const { return Loc; } | |
970d7e83 | 261 | StringRef getFilename() const { return Filename; } |
223e47cc LB |
262 | int getLineNo() const { return LineNo; } |
263 | int getColumnNo() const { return ColumnNo; } | |
264 | SourceMgr::DiagKind getKind() const { return Kind; } | |
970d7e83 LB |
265 | StringRef getMessage() const { return Message; } |
266 | StringRef getLineContents() const { return LineContents; } | |
267 | ArrayRef<std::pair<unsigned, unsigned> > getRanges() const { | |
223e47cc LB |
268 | return Ranges; |
269 | } | |
970d7e83 LB |
270 | |
271 | void addFixIt(const SMFixIt &Hint) { | |
272 | FixIts.push_back(Hint); | |
273 | } | |
274 | ||
275 | ArrayRef<SMFixIt> getFixIts() const { | |
276 | return FixIts; | |
277 | } | |
278 | ||
279 | void print(const char *ProgName, raw_ostream &S, | |
280 | bool ShowColors = true) const; | |
223e47cc LB |
281 | }; |
282 | ||
283 | } // end llvm namespace | |
284 | ||
285 | #endif |