Warning: This file is not a C or C++ file. It does not have highlighting.
1 | //===- SourceLocation.h - Compact identifier for Source Files ---*- 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 | /// \file |
10 | /// Defines the clang::SourceLocation class and associated facilities. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #ifndef LLVM_CLANG_BASIC_SOURCELOCATION_H |
15 | #define LLVM_CLANG_BASIC_SOURCELOCATION_H |
16 | |
17 | #include "clang/Basic/LLVM.h" |
18 | #include "llvm/ADT/StringRef.h" |
19 | #include <cassert> |
20 | #include <cstdint> |
21 | #include <string> |
22 | #include <utility> |
23 | |
24 | namespace llvm { |
25 | |
26 | class FoldingSetNodeID; |
27 | template <typename T, typename Enable> struct FoldingSetTrait; |
28 | |
29 | } // namespace llvm |
30 | |
31 | namespace clang { |
32 | |
33 | class SourceManager; |
34 | |
35 | /// An opaque identifier used by SourceManager which refers to a |
36 | /// source file (MemoryBuffer) along with its \#include path and \#line data. |
37 | /// |
38 | class FileID { |
39 | /// A mostly-opaque identifier, where 0 is "invalid", >0 is |
40 | /// this module, and <-1 is something loaded from another module. |
41 | int ID = 0; |
42 | |
43 | public: |
44 | bool isValid() const { return ID != 0; } |
45 | bool isInvalid() const { return ID == 0; } |
46 | |
47 | bool operator==(const FileID &RHS) const { return ID == RHS.ID; } |
48 | bool operator<(const FileID &RHS) const { return ID < RHS.ID; } |
49 | bool operator<=(const FileID &RHS) const { return ID <= RHS.ID; } |
50 | bool operator!=(const FileID &RHS) const { return !(*this == RHS); } |
51 | bool operator>(const FileID &RHS) const { return RHS < *this; } |
52 | bool operator>=(const FileID &RHS) const { return RHS <= *this; } |
53 | |
54 | static FileID getSentinel() { return get(-1); } |
55 | unsigned getHashValue() const { return static_cast<unsigned>(ID); } |
56 | |
57 | private: |
58 | friend class ASTWriter; |
59 | friend class ASTReader; |
60 | friend class SourceManager; |
61 | |
62 | static FileID get(int V) { |
63 | FileID F; |
64 | F.ID = V; |
65 | return F; |
66 | } |
67 | |
68 | int getOpaqueValue() const { return ID; } |
69 | }; |
70 | |
71 | /// Encodes a location in the source. The SourceManager can decode this |
72 | /// to get at the full include stack, line and column information. |
73 | /// |
74 | /// Technically, a source location is simply an offset into the manager's view |
75 | /// of the input source, which is all input buffers (including macro |
76 | /// expansions) concatenated in an effectively arbitrary order. The manager |
77 | /// actually maintains two blocks of input buffers. One, starting at offset |
78 | /// 0 and growing upwards, contains all buffers from this module. The other, |
79 | /// starting at the highest possible offset and growing downwards, contains |
80 | /// buffers of loaded modules. |
81 | /// |
82 | /// In addition, one bit of SourceLocation is used for quick access to the |
83 | /// information whether the location is in a file or a macro expansion. |
84 | /// |
85 | /// It is important that this type remains small. It is currently 32 bits wide. |
86 | class SourceLocation { |
87 | friend class ASTReader; |
88 | friend class ASTWriter; |
89 | friend class SourceManager; |
90 | friend struct llvm::FoldingSetTrait<SourceLocation, void>; |
91 | |
92 | public: |
93 | using UIntTy = uint32_t; |
94 | using IntTy = int32_t; |
95 | |
96 | private: |
97 | UIntTy ID = 0; |
98 | |
99 | enum : UIntTy { MacroIDBit = 1ULL << (8 * sizeof(UIntTy) - 1) }; |
100 | |
101 | public: |
102 | bool isFileID() const { return (ID & MacroIDBit) == 0; } |
103 | bool isMacroID() const { return (ID & MacroIDBit) != 0; } |
104 | |
105 | /// Return true if this is a valid SourceLocation object. |
106 | /// |
107 | /// Invalid SourceLocations are often used when events have no corresponding |
108 | /// location in the source (e.g. a diagnostic is required for a command line |
109 | /// option). |
110 | bool isValid() const { return ID != 0; } |
111 | bool isInvalid() const { return ID == 0; } |
112 | |
113 | private: |
114 | /// Return the offset into the manager's global input view. |
115 | UIntTy getOffset() const { return ID & ~MacroIDBit; } |
116 | |
117 | static SourceLocation getFileLoc(UIntTy ID) { |
118 | assert((ID & MacroIDBit) == 0 && "Ran out of source locations!"); |
119 | SourceLocation L; |
120 | L.ID = ID; |
121 | return L; |
122 | } |
123 | |
124 | static SourceLocation getMacroLoc(UIntTy ID) { |
125 | assert((ID & MacroIDBit) == 0 && "Ran out of source locations!"); |
126 | SourceLocation L; |
127 | L.ID = MacroIDBit | ID; |
128 | return L; |
129 | } |
130 | |
131 | public: |
132 | /// Return a source location with the specified offset from this |
133 | /// SourceLocation. |
134 | SourceLocation getLocWithOffset(IntTy Offset) const { |
135 | assert(((getOffset()+Offset) & MacroIDBit) == 0 && "offset overflow"); |
136 | SourceLocation L; |
137 | L.ID = ID+Offset; |
138 | return L; |
139 | } |
140 | |
141 | /// When a SourceLocation itself cannot be used, this returns |
142 | /// an (opaque) 32-bit integer encoding for it. |
143 | /// |
144 | /// This should only be passed to SourceLocation::getFromRawEncoding, it |
145 | /// should not be inspected directly. |
146 | UIntTy getRawEncoding() const { return ID; } |
147 | |
148 | /// Turn a raw encoding of a SourceLocation object into |
149 | /// a real SourceLocation. |
150 | /// |
151 | /// \see getRawEncoding. |
152 | static SourceLocation getFromRawEncoding(UIntTy Encoding) { |
153 | SourceLocation X; |
154 | X.ID = Encoding; |
155 | return X; |
156 | } |
157 | |
158 | /// When a SourceLocation itself cannot be used, this returns |
159 | /// an (opaque) pointer encoding for it. |
160 | /// |
161 | /// This should only be passed to SourceLocation::getFromPtrEncoding, it |
162 | /// should not be inspected directly. |
163 | void* getPtrEncoding() const { |
164 | // Double cast to avoid a warning "cast to pointer from integer of different |
165 | // size". |
166 | return (void*)(uintptr_t)getRawEncoding(); |
167 | } |
168 | |
169 | /// Turn a pointer encoding of a SourceLocation object back |
170 | /// into a real SourceLocation. |
171 | static SourceLocation getFromPtrEncoding(const void *Encoding) { |
172 | return getFromRawEncoding((SourceLocation::UIntTy)(uintptr_t)Encoding); |
173 | } |
174 | |
175 | static bool isPairOfFileLocations(SourceLocation Start, SourceLocation End) { |
176 | return Start.isValid() && Start.isFileID() && End.isValid() && |
177 | End.isFileID(); |
178 | } |
179 | |
180 | unsigned getHashValue() const; |
181 | void print(raw_ostream &OS, const SourceManager &SM) const; |
182 | std::string printToString(const SourceManager &SM) const; |
183 | void dump(const SourceManager &SM) const; |
184 | }; |
185 | |
186 | inline bool operator==(const SourceLocation &LHS, const SourceLocation &RHS) { |
187 | return LHS.getRawEncoding() == RHS.getRawEncoding(); |
188 | } |
189 | |
190 | inline bool operator!=(const SourceLocation &LHS, const SourceLocation &RHS) { |
191 | return !(LHS == RHS); |
192 | } |
193 | |
194 | // Ordering is meaningful only if LHS and RHS have the same FileID! |
195 | // Otherwise use SourceManager::isBeforeInTranslationUnit(). |
196 | inline bool operator<(const SourceLocation &LHS, const SourceLocation &RHS) { |
197 | return LHS.getRawEncoding() < RHS.getRawEncoding(); |
198 | } |
199 | inline bool operator>(const SourceLocation &LHS, const SourceLocation &RHS) { |
200 | return LHS.getRawEncoding() > RHS.getRawEncoding(); |
201 | } |
202 | inline bool operator<=(const SourceLocation &LHS, const SourceLocation &RHS) { |
203 | return LHS.getRawEncoding() <= RHS.getRawEncoding(); |
204 | } |
205 | inline bool operator>=(const SourceLocation &LHS, const SourceLocation &RHS) { |
206 | return LHS.getRawEncoding() >= RHS.getRawEncoding(); |
207 | } |
208 | |
209 | /// A trivial tuple used to represent a source range. |
210 | class SourceRange { |
211 | SourceLocation B; |
212 | SourceLocation E; |
213 | |
214 | public: |
215 | SourceRange() = default; |
216 | SourceRange(SourceLocation loc) : B(loc), E(loc) {} |
217 | SourceRange(SourceLocation begin, SourceLocation end) : B(begin), E(end) {} |
218 | |
219 | SourceLocation getBegin() const { return B; } |
220 | SourceLocation getEnd() const { return E; } |
221 | |
222 | void setBegin(SourceLocation b) { B = b; } |
223 | void setEnd(SourceLocation e) { E = e; } |
224 | |
225 | bool isValid() const { return B.isValid() && E.isValid(); } |
226 | bool isInvalid() const { return !isValid(); } |
227 | |
228 | bool operator==(const SourceRange &X) const { |
229 | return B == X.B && E == X.E; |
230 | } |
231 | |
232 | bool operator!=(const SourceRange &X) const { |
233 | return B != X.B || E != X.E; |
234 | } |
235 | |
236 | // Returns true iff other is wholly contained within this range. |
237 | bool fullyContains(const SourceRange &other) const { |
238 | return B <= other.B && E >= other.E; |
239 | } |
240 | |
241 | void print(raw_ostream &OS, const SourceManager &SM) const; |
242 | std::string printToString(const SourceManager &SM) const; |
243 | void dump(const SourceManager &SM) const; |
244 | }; |
245 | |
246 | /// Represents a character-granular source range. |
247 | /// |
248 | /// The underlying SourceRange can either specify the starting/ending character |
249 | /// of the range, or it can specify the start of the range and the start of the |
250 | /// last token of the range (a "token range"). In the token range case, the |
251 | /// size of the last token must be measured to determine the actual end of the |
252 | /// range. |
253 | class CharSourceRange { |
254 | SourceRange Range; |
255 | bool IsTokenRange = false; |
256 | |
257 | public: |
258 | CharSourceRange() = default; |
259 | CharSourceRange(SourceRange R, bool ITR) : Range(R), IsTokenRange(ITR) {} |
260 | |
261 | static CharSourceRange getTokenRange(SourceRange R) { |
262 | return CharSourceRange(R, true); |
263 | } |
264 | |
265 | static CharSourceRange getCharRange(SourceRange R) { |
266 | return CharSourceRange(R, false); |
267 | } |
268 | |
269 | static CharSourceRange getTokenRange(SourceLocation B, SourceLocation E) { |
270 | return getTokenRange(SourceRange(B, E)); |
271 | } |
272 | |
273 | static CharSourceRange getCharRange(SourceLocation B, SourceLocation E) { |
274 | return getCharRange(SourceRange(B, E)); |
275 | } |
276 | |
277 | /// Return true if the end of this range specifies the start of |
278 | /// the last token. Return false if the end of this range specifies the last |
279 | /// character in the range. |
280 | bool isTokenRange() const { return IsTokenRange; } |
281 | bool isCharRange() const { return !IsTokenRange; } |
282 | |
283 | SourceLocation getBegin() const { return Range.getBegin(); } |
284 | SourceLocation getEnd() const { return Range.getEnd(); } |
285 | SourceRange getAsRange() const { return Range; } |
286 | |
287 | void setBegin(SourceLocation b) { Range.setBegin(b); } |
288 | void setEnd(SourceLocation e) { Range.setEnd(e); } |
289 | void setTokenRange(bool TR) { IsTokenRange = TR; } |
290 | |
291 | bool isValid() const { return Range.isValid(); } |
292 | bool isInvalid() const { return !isValid(); } |
293 | }; |
294 | |
295 | /// Represents an unpacked "presumed" location which can be presented |
296 | /// to the user. |
297 | /// |
298 | /// A 'presumed' location can be modified by \#line and GNU line marker |
299 | /// directives and is always the expansion point of a normal location. |
300 | /// |
301 | /// You can get a PresumedLoc from a SourceLocation with SourceManager. |
302 | class PresumedLoc { |
303 | const char *Filename = nullptr; |
304 | FileID ID; |
305 | unsigned Line, Col; |
306 | SourceLocation IncludeLoc; |
307 | |
308 | public: |
309 | PresumedLoc() = default; |
310 | PresumedLoc(const char *FN, FileID FID, unsigned Ln, unsigned Co, |
311 | SourceLocation IL) |
312 | : Filename(FN), ID(FID), Line(Ln), Col(Co), IncludeLoc(IL) {} |
313 | |
314 | /// Return true if this object is invalid or uninitialized. |
315 | /// |
316 | /// This occurs when created with invalid source locations or when walking |
317 | /// off the top of a \#include stack. |
318 | bool isInvalid() const { return Filename == nullptr; } |
319 | bool isValid() const { return Filename != nullptr; } |
320 | |
321 | /// Return the presumed filename of this location. |
322 | /// |
323 | /// This can be affected by \#line etc. |
324 | const char *getFilename() const { |
325 | assert(isValid()); |
326 | return Filename; |
327 | } |
328 | |
329 | FileID getFileID() const { |
330 | assert(isValid()); |
331 | return ID; |
332 | } |
333 | |
334 | /// Return the presumed line number of this location. |
335 | /// |
336 | /// This can be affected by \#line etc. |
337 | unsigned getLine() const { |
338 | assert(isValid()); |
339 | return Line; |
340 | } |
341 | |
342 | /// Return the presumed column number of this location. |
343 | /// |
344 | /// This cannot be affected by \#line, but is packaged here for convenience. |
345 | unsigned getColumn() const { |
346 | assert(isValid()); |
347 | return Col; |
348 | } |
349 | |
350 | /// Return the presumed include location of this location. |
351 | /// |
352 | /// This can be affected by GNU linemarker directives. |
353 | SourceLocation getIncludeLoc() const { |
354 | assert(isValid()); |
355 | return IncludeLoc; |
356 | } |
357 | }; |
358 | |
359 | class FileEntry; |
360 | |
361 | /// A SourceLocation and its associated SourceManager. |
362 | /// |
363 | /// This is useful for argument passing to functions that expect both objects. |
364 | /// |
365 | /// This class does not guarantee the presence of either the SourceManager or |
366 | /// a valid SourceLocation. Clients should use `isValid()` and `hasManager()` |
367 | /// before calling the member functions. |
368 | class FullSourceLoc : public SourceLocation { |
369 | const SourceManager *SrcMgr = nullptr; |
370 | |
371 | public: |
372 | /// Creates a FullSourceLoc where isValid() returns \c false. |
373 | FullSourceLoc() = default; |
374 | |
375 | explicit FullSourceLoc(SourceLocation Loc, const SourceManager &SM) |
376 | : SourceLocation(Loc), SrcMgr(&SM) {} |
377 | |
378 | /// Checks whether the SourceManager is present. |
379 | bool hasManager() const { return SrcMgr != nullptr; } |
380 | |
381 | /// \pre hasManager() |
382 | const SourceManager &getManager() const { |
383 | assert(SrcMgr && "SourceManager is NULL."); |
384 | return *SrcMgr; |
385 | } |
386 | |
387 | FileID getFileID() const; |
388 | |
389 | FullSourceLoc getExpansionLoc() const; |
390 | FullSourceLoc getSpellingLoc() const; |
391 | FullSourceLoc getFileLoc() const; |
392 | PresumedLoc getPresumedLoc(bool UseLineDirectives = true) const; |
393 | bool isMacroArgExpansion(FullSourceLoc *StartLoc = nullptr) const; |
394 | FullSourceLoc getImmediateMacroCallerLoc() const; |
395 | std::pair<FullSourceLoc, StringRef> getModuleImportLoc() const; |
396 | unsigned getFileOffset() const; |
397 | |
398 | unsigned getExpansionLineNumber(bool *Invalid = nullptr) const; |
399 | unsigned getExpansionColumnNumber(bool *Invalid = nullptr) const; |
400 | |
401 | /// Decompose the underlying \c SourceLocation into a raw (FileID + Offset) |
402 | /// pair, after walking through all expansion records. |
403 | /// |
404 | /// \see SourceManager::getDecomposedExpansionLoc |
405 | std::pair<FileID, unsigned> getDecomposedExpansionLoc() const; |
406 | |
407 | unsigned getSpellingLineNumber(bool *Invalid = nullptr) const; |
408 | unsigned getSpellingColumnNumber(bool *Invalid = nullptr) const; |
409 | |
410 | const char *getCharacterData(bool *Invalid = nullptr) const; |
411 | |
412 | unsigned getLineNumber(bool *Invalid = nullptr) const; |
413 | unsigned getColumnNumber(bool *Invalid = nullptr) const; |
414 | |
415 | const FileEntry *getFileEntry() const; |
416 | |
417 | /// Return a StringRef to the source buffer data for the |
418 | /// specified FileID. |
419 | StringRef getBufferData(bool *Invalid = nullptr) const; |
420 | |
421 | /// Decompose the specified location into a raw FileID + Offset pair. |
422 | /// |
423 | /// The first element is the FileID, the second is the offset from the |
424 | /// start of the buffer of the location. |
425 | std::pair<FileID, unsigned> getDecomposedLoc() const; |
426 | |
427 | bool isInSystemHeader() const; |
428 | |
429 | /// Determines the order of 2 source locations in the translation unit. |
430 | /// |
431 | /// \returns true if this source location comes before 'Loc', false otherwise. |
432 | bool isBeforeInTranslationUnitThan(SourceLocation Loc) const; |
433 | |
434 | /// Determines the order of 2 source locations in the translation unit. |
435 | /// |
436 | /// \returns true if this source location comes before 'Loc', false otherwise. |
437 | bool isBeforeInTranslationUnitThan(FullSourceLoc Loc) const { |
438 | assert(Loc.isValid()); |
439 | assert(SrcMgr == Loc.SrcMgr && "Loc comes from another SourceManager!"); |
440 | return isBeforeInTranslationUnitThan((SourceLocation)Loc); |
441 | } |
442 | |
443 | /// Comparison function class, useful for sorting FullSourceLocs. |
444 | struct BeforeThanCompare { |
445 | bool operator()(const FullSourceLoc& lhs, const FullSourceLoc& rhs) const { |
446 | return lhs.isBeforeInTranslationUnitThan(rhs); |
447 | } |
448 | }; |
449 | |
450 | /// Prints information about this FullSourceLoc to stderr. |
451 | /// |
452 | /// This is useful for debugging. |
453 | void dump() const; |
454 | |
455 | friend bool |
456 | operator==(const FullSourceLoc &LHS, const FullSourceLoc &RHS) { |
457 | return LHS.getRawEncoding() == RHS.getRawEncoding() && |
458 | LHS.SrcMgr == RHS.SrcMgr; |
459 | } |
460 | |
461 | friend bool |
462 | operator!=(const FullSourceLoc &LHS, const FullSourceLoc &RHS) { |
463 | return !(LHS == RHS); |
464 | } |
465 | }; |
466 | |
467 | } // namespace clang |
468 | |
469 | namespace llvm { |
470 | |
471 | /// Define DenseMapInfo so that FileID's can be used as keys in DenseMap and |
472 | /// DenseSets. |
473 | template <> |
474 | struct DenseMapInfo<clang::FileID, void> { |
475 | static clang::FileID getEmptyKey() { |
476 | return {}; |
477 | } |
478 | |
479 | static clang::FileID getTombstoneKey() { |
480 | return clang::FileID::getSentinel(); |
481 | } |
482 | |
483 | static unsigned getHashValue(clang::FileID S) { |
484 | return S.getHashValue(); |
485 | } |
486 | |
487 | static bool isEqual(clang::FileID LHS, clang::FileID RHS) { |
488 | return LHS == RHS; |
489 | } |
490 | }; |
491 | |
492 | /// Define DenseMapInfo so that SourceLocation's can be used as keys in |
493 | /// DenseMap and DenseSet. This trait class is eqivalent to |
494 | /// DenseMapInfo<unsigned> which uses SourceLocation::ID is used as a key. |
495 | template <> struct DenseMapInfo<clang::SourceLocation, void> { |
496 | static clang::SourceLocation getEmptyKey() { |
497 | constexpr clang::SourceLocation::UIntTy Zero = 0; |
498 | return clang::SourceLocation::getFromRawEncoding(~Zero); |
499 | } |
500 | |
501 | static clang::SourceLocation getTombstoneKey() { |
502 | constexpr clang::SourceLocation::UIntTy Zero = 0; |
503 | return clang::SourceLocation::getFromRawEncoding(~Zero - 1); |
504 | } |
505 | |
506 | static unsigned getHashValue(clang::SourceLocation Loc) { |
507 | return Loc.getHashValue(); |
508 | } |
509 | |
510 | static bool isEqual(clang::SourceLocation LHS, clang::SourceLocation RHS) { |
511 | return LHS == RHS; |
512 | } |
513 | }; |
514 | |
515 | // Allow calling FoldingSetNodeID::Add with SourceLocation object as parameter |
516 | template <> struct FoldingSetTrait<clang::SourceLocation, void> { |
517 | static void Profile(const clang::SourceLocation &X, FoldingSetNodeID &ID); |
518 | }; |
519 | |
520 | } // namespace llvm |
521 | |
522 | #endif // LLVM_CLANG_BASIC_SOURCELOCATION_H |
523 |
Warning: This file is not a C or C++ file. It does not have highlighting.