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 "llvm/Support/PointerLikeTypeTraits.h" 20 #include <cassert> 21 #include <cstdint> 22 #include <string> 23 #include <utility> 24 25 namespace llvm { 26 27 template <typename T> struct DenseMapInfo; 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: isValid()44 bool isValid() const { return ID != 0; } isInvalid()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 getSentinel()54 static FileID getSentinel() { return get(-1); } getHashValue()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 get(int V)62 static FileID get(int V) { 63 FileID F; 64 F.ID = V; 65 return F; 66 } 67 getOpaqueValue()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 91 unsigned ID = 0; 92 93 enum : unsigned { 94 MacroIDBit = 1U << 31 95 }; 96 97 public: isFileID()98 bool isFileID() const { return (ID & MacroIDBit) == 0; } isMacroID()99 bool isMacroID() const { return (ID & MacroIDBit) != 0; } 100 101 /// Return true if this is a valid SourceLocation object. 102 /// 103 /// Invalid SourceLocations are often used when events have no corresponding 104 /// location in the source (e.g. a diagnostic is required for a command line 105 /// option). isValid()106 bool isValid() const { return ID != 0; } isInvalid()107 bool isInvalid() const { return ID == 0; } 108 109 private: 110 /// Return the offset into the manager's global input view. getOffset()111 unsigned getOffset() const { 112 return ID & ~MacroIDBit; 113 } 114 getFileLoc(unsigned ID)115 static SourceLocation getFileLoc(unsigned ID) { 116 assert((ID & MacroIDBit) == 0 && "Ran out of source locations!"); 117 SourceLocation L; 118 L.ID = ID; 119 return L; 120 } 121 getMacroLoc(unsigned ID)122 static SourceLocation getMacroLoc(unsigned ID) { 123 assert((ID & MacroIDBit) == 0 && "Ran out of source locations!"); 124 SourceLocation L; 125 L.ID = MacroIDBit | ID; 126 return L; 127 } 128 129 public: 130 /// Return a source location with the specified offset from this 131 /// SourceLocation. getLocWithOffset(int Offset)132 SourceLocation getLocWithOffset(int Offset) const { 133 assert(((getOffset()+Offset) & MacroIDBit) == 0 && "offset overflow"); 134 SourceLocation L; 135 L.ID = ID+Offset; 136 return L; 137 } 138 139 /// When a SourceLocation itself cannot be used, this returns 140 /// an (opaque) 32-bit integer encoding for it. 141 /// 142 /// This should only be passed to SourceLocation::getFromRawEncoding, it 143 /// should not be inspected directly. getRawEncoding()144 unsigned getRawEncoding() const { return ID; } 145 146 /// Turn a raw encoding of a SourceLocation object into 147 /// a real SourceLocation. 148 /// 149 /// \see getRawEncoding. getFromRawEncoding(unsigned Encoding)150 static SourceLocation getFromRawEncoding(unsigned Encoding) { 151 SourceLocation X; 152 X.ID = Encoding; 153 return X; 154 } 155 156 /// When a SourceLocation itself cannot be used, this returns 157 /// an (opaque) pointer encoding for it. 158 /// 159 /// This should only be passed to SourceLocation::getFromPtrEncoding, it 160 /// should not be inspected directly. getPtrEncoding()161 void* getPtrEncoding() const { 162 // Double cast to avoid a warning "cast to pointer from integer of different 163 // size". 164 return (void*)(uintptr_t)getRawEncoding(); 165 } 166 167 /// Turn a pointer encoding of a SourceLocation object back 168 /// into a real SourceLocation. getFromPtrEncoding(const void * Encoding)169 static SourceLocation getFromPtrEncoding(const void *Encoding) { 170 return getFromRawEncoding((unsigned)(uintptr_t)Encoding); 171 } 172 isPairOfFileLocations(SourceLocation Start,SourceLocation End)173 static bool isPairOfFileLocations(SourceLocation Start, SourceLocation End) { 174 return Start.isValid() && Start.isFileID() && End.isValid() && 175 End.isFileID(); 176 } 177 178 void print(raw_ostream &OS, const SourceManager &SM) const; 179 std::string printToString(const SourceManager &SM) const; 180 void dump(const SourceManager &SM) const; 181 }; 182 183 inline bool operator==(const SourceLocation &LHS, const SourceLocation &RHS) { 184 return LHS.getRawEncoding() == RHS.getRawEncoding(); 185 } 186 187 inline bool operator!=(const SourceLocation &LHS, const SourceLocation &RHS) { 188 return !(LHS == RHS); 189 } 190 191 inline bool operator<(const SourceLocation &LHS, const SourceLocation &RHS) { 192 return LHS.getRawEncoding() < RHS.getRawEncoding(); 193 } 194 195 /// A trivial tuple used to represent a source range. 196 class SourceRange { 197 SourceLocation B; 198 SourceLocation E; 199 200 public: 201 SourceRange() = default; SourceRange(SourceLocation loc)202 SourceRange(SourceLocation loc) : B(loc), E(loc) {} SourceRange(SourceLocation begin,SourceLocation end)203 SourceRange(SourceLocation begin, SourceLocation end) : B(begin), E(end) {} 204 getBegin()205 SourceLocation getBegin() const { return B; } getEnd()206 SourceLocation getEnd() const { return E; } 207 setBegin(SourceLocation b)208 void setBegin(SourceLocation b) { B = b; } setEnd(SourceLocation e)209 void setEnd(SourceLocation e) { E = e; } 210 isValid()211 bool isValid() const { return B.isValid() && E.isValid(); } isInvalid()212 bool isInvalid() const { return !isValid(); } 213 214 bool operator==(const SourceRange &X) const { 215 return B == X.B && E == X.E; 216 } 217 218 bool operator!=(const SourceRange &X) const { 219 return B != X.B || E != X.E; 220 } 221 222 void print(raw_ostream &OS, const SourceManager &SM) const; 223 std::string printToString(const SourceManager &SM) const; 224 void dump(const SourceManager &SM) const; 225 }; 226 227 /// Represents a character-granular source range. 228 /// 229 /// The underlying SourceRange can either specify the starting/ending character 230 /// of the range, or it can specify the start of the range and the start of the 231 /// last token of the range (a "token range"). In the token range case, the 232 /// size of the last token must be measured to determine the actual end of the 233 /// range. 234 class CharSourceRange { 235 SourceRange Range; 236 bool IsTokenRange = false; 237 238 public: 239 CharSourceRange() = default; CharSourceRange(SourceRange R,bool ITR)240 CharSourceRange(SourceRange R, bool ITR) : Range(R), IsTokenRange(ITR) {} 241 getTokenRange(SourceRange R)242 static CharSourceRange getTokenRange(SourceRange R) { 243 return CharSourceRange(R, true); 244 } 245 getCharRange(SourceRange R)246 static CharSourceRange getCharRange(SourceRange R) { 247 return CharSourceRange(R, false); 248 } 249 getTokenRange(SourceLocation B,SourceLocation E)250 static CharSourceRange getTokenRange(SourceLocation B, SourceLocation E) { 251 return getTokenRange(SourceRange(B, E)); 252 } 253 getCharRange(SourceLocation B,SourceLocation E)254 static CharSourceRange getCharRange(SourceLocation B, SourceLocation E) { 255 return getCharRange(SourceRange(B, E)); 256 } 257 258 /// Return true if the end of this range specifies the start of 259 /// the last token. Return false if the end of this range specifies the last 260 /// character in the range. isTokenRange()261 bool isTokenRange() const { return IsTokenRange; } isCharRange()262 bool isCharRange() const { return !IsTokenRange; } 263 getBegin()264 SourceLocation getBegin() const { return Range.getBegin(); } getEnd()265 SourceLocation getEnd() const { return Range.getEnd(); } getAsRange()266 SourceRange getAsRange() const { return Range; } 267 setBegin(SourceLocation b)268 void setBegin(SourceLocation b) { Range.setBegin(b); } setEnd(SourceLocation e)269 void setEnd(SourceLocation e) { Range.setEnd(e); } setTokenRange(bool TR)270 void setTokenRange(bool TR) { IsTokenRange = TR; } 271 isValid()272 bool isValid() const { return Range.isValid(); } isInvalid()273 bool isInvalid() const { return !isValid(); } 274 }; 275 276 /// Represents an unpacked "presumed" location which can be presented 277 /// to the user. 278 /// 279 /// A 'presumed' location can be modified by \#line and GNU line marker 280 /// directives and is always the expansion point of a normal location. 281 /// 282 /// You can get a PresumedLoc from a SourceLocation with SourceManager. 283 class PresumedLoc { 284 const char *Filename = nullptr; 285 FileID ID; 286 unsigned Line, Col; 287 SourceLocation IncludeLoc; 288 289 public: 290 PresumedLoc() = default; PresumedLoc(const char * FN,FileID FID,unsigned Ln,unsigned Co,SourceLocation IL)291 PresumedLoc(const char *FN, FileID FID, unsigned Ln, unsigned Co, 292 SourceLocation IL) 293 : Filename(FN), ID(FID), 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 getFileID()310 FileID getFileID() const { 311 assert(isValid()); 312 return ID; 313 } 314 315 /// Return the presumed line number of this location. 316 /// 317 /// This can be affected by \#line etc. getLine()318 unsigned getLine() const { 319 assert(isValid()); 320 return Line; 321 } 322 323 /// Return the presumed column number of this location. 324 /// 325 /// This cannot be affected by \#line, but is packaged here for convenience. getColumn()326 unsigned getColumn() const { 327 assert(isValid()); 328 return Col; 329 } 330 331 /// Return the presumed include location of this location. 332 /// 333 /// This can be affected by GNU linemarker directives. getIncludeLoc()334 SourceLocation getIncludeLoc() const { 335 assert(isValid()); 336 return IncludeLoc; 337 } 338 }; 339 340 class FileEntry; 341 342 /// A SourceLocation and its associated SourceManager. 343 /// 344 /// This is useful for argument passing to functions that expect both objects. 345 class FullSourceLoc : public SourceLocation { 346 const SourceManager *SrcMgr = nullptr; 347 348 public: 349 /// Creates a FullSourceLoc where isValid() returns \c false. 350 FullSourceLoc() = default; 351 FullSourceLoc(SourceLocation Loc,const SourceManager & SM)352 explicit FullSourceLoc(SourceLocation Loc, const SourceManager &SM) 353 : SourceLocation(Loc), SrcMgr(&SM) {} 354 hasManager()355 bool hasManager() const { 356 bool hasSrcMgr = SrcMgr != nullptr; 357 assert(hasSrcMgr == isValid() && "FullSourceLoc has location but no manager"); 358 return hasSrcMgr; 359 } 360 361 /// \pre This FullSourceLoc has an associated SourceManager. getManager()362 const SourceManager &getManager() const { 363 assert(SrcMgr && "SourceManager is NULL."); 364 return *SrcMgr; 365 } 366 367 FileID getFileID() const; 368 369 FullSourceLoc getExpansionLoc() const; 370 FullSourceLoc getSpellingLoc() const; 371 FullSourceLoc getFileLoc() const; 372 PresumedLoc getPresumedLoc(bool UseLineDirectives = true) const; 373 bool isMacroArgExpansion(FullSourceLoc *StartLoc = nullptr) const; 374 FullSourceLoc getImmediateMacroCallerLoc() const; 375 std::pair<FullSourceLoc, StringRef> getModuleImportLoc() const; 376 unsigned getFileOffset() const; 377 378 unsigned getExpansionLineNumber(bool *Invalid = nullptr) const; 379 unsigned getExpansionColumnNumber(bool *Invalid = nullptr) const; 380 381 unsigned getSpellingLineNumber(bool *Invalid = nullptr) const; 382 unsigned getSpellingColumnNumber(bool *Invalid = nullptr) const; 383 384 const char *getCharacterData(bool *Invalid = nullptr) const; 385 386 unsigned getLineNumber(bool *Invalid = nullptr) const; 387 unsigned getColumnNumber(bool *Invalid = nullptr) const; 388 389 const FileEntry *getFileEntry() const; 390 391 /// Return a StringRef to the source buffer data for the 392 /// specified FileID. 393 StringRef getBufferData(bool *Invalid = nullptr) const; 394 395 /// Decompose the specified location into a raw FileID + Offset pair. 396 /// 397 /// The first element is the FileID, the second is the offset from the 398 /// start of the buffer of the location. 399 std::pair<FileID, unsigned> getDecomposedLoc() const; 400 401 bool isInSystemHeader() 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. 406 bool isBeforeInTranslationUnitThan(SourceLocation Loc) const; 407 408 /// Determines the order of 2 source locations in the translation unit. 409 /// 410 /// \returns true if this source location comes before 'Loc', false otherwise. isBeforeInTranslationUnitThan(FullSourceLoc Loc)411 bool isBeforeInTranslationUnitThan(FullSourceLoc Loc) const { 412 assert(Loc.isValid()); 413 assert(SrcMgr == Loc.SrcMgr && "Loc comes from another SourceManager!"); 414 return isBeforeInTranslationUnitThan((SourceLocation)Loc); 415 } 416 417 /// Comparison function class, useful for sorting FullSourceLocs. 418 struct BeforeThanCompare { operatorBeforeThanCompare419 bool operator()(const FullSourceLoc& lhs, const FullSourceLoc& rhs) const { 420 return lhs.isBeforeInTranslationUnitThan(rhs); 421 } 422 }; 423 424 /// Prints information about this FullSourceLoc to stderr. 425 /// 426 /// This is useful for debugging. 427 void dump() const; 428 429 friend bool 430 operator==(const FullSourceLoc &LHS, const FullSourceLoc &RHS) { 431 return LHS.getRawEncoding() == RHS.getRawEncoding() && 432 LHS.SrcMgr == RHS.SrcMgr; 433 } 434 435 friend bool 436 operator!=(const FullSourceLoc &LHS, const FullSourceLoc &RHS) { 437 return !(LHS == RHS); 438 } 439 }; 440 441 } // namespace clang 442 443 namespace llvm { 444 445 /// Define DenseMapInfo so that FileID's can be used as keys in DenseMap and 446 /// DenseSets. 447 template <> 448 struct DenseMapInfo<clang::FileID> { 449 static clang::FileID getEmptyKey() { 450 return {}; 451 } 452 453 static clang::FileID getTombstoneKey() { 454 return clang::FileID::getSentinel(); 455 } 456 457 static unsigned getHashValue(clang::FileID S) { 458 return S.getHashValue(); 459 } 460 461 static bool isEqual(clang::FileID LHS, clang::FileID RHS) { 462 return LHS == RHS; 463 } 464 }; 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