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 unsigned getSpellingLineNumber(bool *Invalid = nullptr) const; 402 unsigned getSpellingColumnNumber(bool *Invalid = nullptr) const; 403 404 const char *getCharacterData(bool *Invalid = nullptr) const; 405 406 unsigned getLineNumber(bool *Invalid = nullptr) const; 407 unsigned getColumnNumber(bool *Invalid = nullptr) const; 408 409 const FileEntry *getFileEntry() const; 410 411 /// Return a StringRef to the source buffer data for the 412 /// specified FileID. 413 StringRef getBufferData(bool *Invalid = nullptr) const; 414 415 /// Decompose the specified location into a raw FileID + Offset pair. 416 /// 417 /// The first element is the FileID, the second is the offset from the 418 /// start of the buffer of the location. 419 std::pair<FileID, unsigned> getDecomposedLoc() const; 420 421 bool isInSystemHeader() const; 422 423 /// Determines the order of 2 source locations in the translation unit. 424 /// 425 /// \returns true if this source location comes before 'Loc', false otherwise. 426 bool isBeforeInTranslationUnitThan(SourceLocation Loc) const; 427 428 /// Determines the order of 2 source locations in the translation unit. 429 /// 430 /// \returns true if this source location comes before 'Loc', false otherwise. 431 bool isBeforeInTranslationUnitThan(FullSourceLoc Loc) const { 432 assert(Loc.isValid()); 433 assert(SrcMgr == Loc.SrcMgr && "Loc comes from another SourceManager!"); 434 return isBeforeInTranslationUnitThan((SourceLocation)Loc); 435 } 436 437 /// Comparison function class, useful for sorting FullSourceLocs. 438 struct BeforeThanCompare { 439 bool operator()(const FullSourceLoc& lhs, const FullSourceLoc& rhs) const { 440 return lhs.isBeforeInTranslationUnitThan(rhs); 441 } 442 }; 443 444 /// Prints information about this FullSourceLoc to stderr. 445 /// 446 /// This is useful for debugging. 447 void dump() const; 448 449 friend bool 450 operator==(const FullSourceLoc &LHS, const FullSourceLoc &RHS) { 451 return LHS.getRawEncoding() == RHS.getRawEncoding() && 452 LHS.SrcMgr == RHS.SrcMgr; 453 } 454 455 friend bool 456 operator!=(const FullSourceLoc &LHS, const FullSourceLoc &RHS) { 457 return !(LHS == RHS); 458 } 459 }; 460 461 } // namespace clang 462 463 namespace llvm { 464 465 /// Define DenseMapInfo so that FileID's can be used as keys in DenseMap and 466 /// DenseSets. 467 template <> 468 struct DenseMapInfo<clang::FileID, void> { 469 static clang::FileID getEmptyKey() { 470 return {}; 471 } 472 473 static clang::FileID getTombstoneKey() { 474 return clang::FileID::getSentinel(); 475 } 476 477 static unsigned getHashValue(clang::FileID S) { 478 return S.getHashValue(); 479 } 480 481 static bool isEqual(clang::FileID LHS, clang::FileID RHS) { 482 return LHS == RHS; 483 } 484 }; 485 486 /// Define DenseMapInfo so that SourceLocation's can be used as keys in 487 /// DenseMap and DenseSet. This trait class is eqivalent to 488 /// DenseMapInfo<unsigned> which uses SourceLocation::ID is used as a key. 489 template <> struct DenseMapInfo<clang::SourceLocation, void> { 490 static clang::SourceLocation getEmptyKey() { 491 constexpr clang::SourceLocation::UIntTy Zero = 0; 492 return clang::SourceLocation::getFromRawEncoding(~Zero); 493 } 494 495 static clang::SourceLocation getTombstoneKey() { 496 constexpr clang::SourceLocation::UIntTy Zero = 0; 497 return clang::SourceLocation::getFromRawEncoding(~Zero - 1); 498 } 499 500 static unsigned getHashValue(clang::SourceLocation Loc) { 501 return Loc.getHashValue(); 502 } 503 504 static bool isEqual(clang::SourceLocation LHS, clang::SourceLocation RHS) { 505 return LHS == RHS; 506 } 507 }; 508 509 // Allow calling FoldingSetNodeID::Add with SourceLocation object as parameter 510 template <> struct FoldingSetTrait<clang::SourceLocation, void> { 511 static void Profile(const clang::SourceLocation &X, FoldingSetNodeID &ID); 512 }; 513 514 } // namespace llvm 515 516 #endif // LLVM_CLANG_BASIC_SOURCELOCATION_H 517