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
24namespace llvm {
25
26class FoldingSetNodeID;
27template <typename T, typename Enable> struct FoldingSetTrait;
28
29} // namespace llvm
30
31namespace clang {
32
33class 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///
38class 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
43public:
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
57private:
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.
86class SourceLocation {
87 friend class ASTReader;
88 friend class ASTWriter;
89 friend class SourceManager;
90 friend struct llvm::FoldingSetTrait<SourceLocation, void>;
91
92public:
93 using UIntTy = uint32_t;
94 using IntTy = int32_t;
95
96private:
97 UIntTy ID = 0;
98
99 enum : UIntTy { MacroIDBit = 1ULL << (8 * sizeof(UIntTy) - 1) };
100
101public:
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
113private:
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
131public:
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
186inline bool operator==(const SourceLocation &LHS, const SourceLocation &RHS) {
187 return LHS.getRawEncoding() == RHS.getRawEncoding();
188}
189
190inline 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().
196inline bool operator<(const SourceLocation &LHS, const SourceLocation &RHS) {
197 return LHS.getRawEncoding() < RHS.getRawEncoding();
198}
199inline bool operator>(const SourceLocation &LHS, const SourceLocation &RHS) {
200 return LHS.getRawEncoding() > RHS.getRawEncoding();
201}
202inline bool operator<=(const SourceLocation &LHS, const SourceLocation &RHS) {
203 return LHS.getRawEncoding() <= RHS.getRawEncoding();
204}
205inline 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.
210class SourceRange {
211 SourceLocation B;
212 SourceLocation E;
213
214public:
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.
253class CharSourceRange {
254 SourceRange Range;
255 bool IsTokenRange = false;
256
257public:
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.
302class PresumedLoc {
303 const char *Filename = nullptr;
304 FileID ID;
305 unsigned Line, Col;
306 SourceLocation IncludeLoc;
307
308public:
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
359class 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.
368class FullSourceLoc : public SourceLocation {
369 const SourceManager *SrcMgr = nullptr;
370
371public:
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
469namespace 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