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