Reid Spencer | 5f016e2 | 2007-07-11 17:01:13 +0000 | [diff] [blame] | 1 | //===--- SourceLocation.h - Compact identifier for Source Files -*- C++ -*-===// |
| 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file was developed by Chris Lattner and is distributed under |
| 6 | // the University of Illinois Open Source License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | // |
| 10 | // This file defines the SourceLocation class. |
| 11 | // |
| 12 | //===----------------------------------------------------------------------===// |
| 13 | |
| 14 | #ifndef LLVM_CLANG_SOURCELOCATION_H |
| 15 | #define LLVM_CLANG_SOURCELOCATION_H |
| 16 | |
Chris Lattner | 9dc1f53 | 2007-07-20 16:37:10 +0000 | [diff] [blame] | 17 | #include <cassert> |
Ted Kremenek | 0a449ee | 2007-10-25 18:27:10 +0000 | [diff] [blame^] | 18 | #include "llvm/Bitcode/SerializationFwd.h" |
Chris Lattner | 9dc1f53 | 2007-07-20 16:37:10 +0000 | [diff] [blame] | 19 | |
Reid Spencer | 5f016e2 | 2007-07-11 17:01:13 +0000 | [diff] [blame] | 20 | namespace clang { |
| 21 | |
| 22 | /// SourceLocation - This is a carefully crafted 32-bit identifier that encodes |
| 23 | /// a full include stack, line and column number information for a position in |
| 24 | /// an input translation unit. |
| 25 | class SourceLocation { |
| 26 | unsigned ID; |
| 27 | public: |
| 28 | enum { |
| 29 | FileIDBits = 14, |
Chris Lattner | 9dc1f53 | 2007-07-20 16:37:10 +0000 | [diff] [blame] | 30 | FilePosBits = 32-1-FileIDBits, |
| 31 | |
Chris Lattner | d1623a8 | 2007-07-21 06:41:57 +0000 | [diff] [blame] | 32 | MacroIDBits = 20, |
Chris Lattner | 31bb8be | 2007-07-20 18:00:12 +0000 | [diff] [blame] | 33 | MacroPhysOffsBits = 9, |
Chris Lattner | 2c64b7b | 2007-10-16 21:07:07 +0000 | [diff] [blame] | 34 | MacroLogOffBits = 2, |
| 35 | |
| 36 | ChunkSize = (1 << FilePosBits) |
Reid Spencer | 5f016e2 | 2007-07-11 17:01:13 +0000 | [diff] [blame] | 37 | }; |
| 38 | |
| 39 | SourceLocation() : ID(0) {} // 0 is an invalid FileID. |
| 40 | |
Chris Lattner | 9dc1f53 | 2007-07-20 16:37:10 +0000 | [diff] [blame] | 41 | bool isFileID() const { return (ID >> 31) == 0; } |
| 42 | bool isMacroID() const { return (ID >> 31) != 0; } |
| 43 | |
| 44 | static SourceLocation getFileLoc(unsigned FileID, unsigned FilePos) { |
| 45 | SourceLocation L; |
Reid Spencer | 5f016e2 | 2007-07-11 17:01:13 +0000 | [diff] [blame] | 46 | // If a FilePos is larger than (1<<FilePosBits), the SourceManager makes |
| 47 | // enough consequtive FileIDs that we have one for each chunk. |
Chris Lattner | 2c64b7b | 2007-10-16 21:07:07 +0000 | [diff] [blame] | 48 | if (FilePos >= ChunkSize) { |
Reid Spencer | 5f016e2 | 2007-07-11 17:01:13 +0000 | [diff] [blame] | 49 | FileID += FilePos >> FilePosBits; |
Chris Lattner | 2c64b7b | 2007-10-16 21:07:07 +0000 | [diff] [blame] | 50 | FilePos &= ChunkSize-1; |
Reid Spencer | 5f016e2 | 2007-07-11 17:01:13 +0000 | [diff] [blame] | 51 | } |
| 52 | |
| 53 | // FIXME: Find a way to handle out of FileID bits! Maybe MaxFileID is an |
| 54 | // escape of some sort? |
Chris Lattner | 4cabcfe | 2007-08-02 04:14:33 +0000 | [diff] [blame] | 55 | assert(FileID < (1 << FileIDBits) && "Out of fileid's"); |
Reid Spencer | 5f016e2 | 2007-07-11 17:01:13 +0000 | [diff] [blame] | 56 | |
Chris Lattner | 9dc1f53 | 2007-07-20 16:37:10 +0000 | [diff] [blame] | 57 | L.ID = (FileID << FilePosBits) | FilePos; |
| 58 | return L; |
Reid Spencer | 5f016e2 | 2007-07-11 17:01:13 +0000 | [diff] [blame] | 59 | } |
| 60 | |
Chris Lattner | d1623a8 | 2007-07-21 06:41:57 +0000 | [diff] [blame] | 61 | static bool isValidMacroPhysOffs(int Val) { |
| 62 | if (Val >= 0) |
| 63 | return Val < (1 << (MacroPhysOffsBits-1)); |
| 64 | return -Val < (1 << (MacroPhysOffsBits-1)); |
| 65 | } |
| 66 | |
| 67 | static SourceLocation getMacroLoc(unsigned MacroID, int PhysOffs, |
Chris Lattner | 9dc1f53 | 2007-07-20 16:37:10 +0000 | [diff] [blame] | 68 | unsigned LogOffs) { |
Chris Lattner | 9dc1f53 | 2007-07-20 16:37:10 +0000 | [diff] [blame] | 69 | assert(MacroID < (1 << MacroIDBits) && "Too many macros!"); |
Chris Lattner | d1623a8 | 2007-07-21 06:41:57 +0000 | [diff] [blame] | 70 | assert(isValidMacroPhysOffs(PhysOffs) && "Physoffs too large!"); |
Chris Lattner | 9dc1f53 | 2007-07-20 16:37:10 +0000 | [diff] [blame] | 71 | assert(LogOffs < (1 << MacroLogOffBits) && "Logical offs too large!"); |
| 72 | |
Chris Lattner | d1623a8 | 2007-07-21 06:41:57 +0000 | [diff] [blame] | 73 | PhysOffs &= (1 << MacroPhysOffsBits)-1; |
| 74 | |
| 75 | SourceLocation L; |
Chris Lattner | 9dc1f53 | 2007-07-20 16:37:10 +0000 | [diff] [blame] | 76 | L.ID = (1 << 31) | (MacroID << (MacroPhysOffsBits+MacroLogOffBits)) | |
Chris Lattner | d1623a8 | 2007-07-21 06:41:57 +0000 | [diff] [blame] | 77 | (PhysOffs << MacroLogOffBits) | |
| 78 | LogOffs; |
Chris Lattner | 9dc1f53 | 2007-07-20 16:37:10 +0000 | [diff] [blame] | 79 | return L; |
| 80 | } |
| 81 | |
| 82 | |
Reid Spencer | 5f016e2 | 2007-07-11 17:01:13 +0000 | [diff] [blame] | 83 | /// isValid - Return true if this is a valid SourceLocation object. Invalid |
| 84 | /// SourceLocations are often used when events have no corresponding location |
| 85 | /// in the source (e.g. a diagnostic is required for a command line option). |
| 86 | /// |
| 87 | bool isValid() const { return ID != 0; } |
Chris Lattner | 9dc1f53 | 2007-07-20 16:37:10 +0000 | [diff] [blame] | 88 | bool isInvalid() const { return ID == 0; } |
Reid Spencer | 5f016e2 | 2007-07-11 17:01:13 +0000 | [diff] [blame] | 89 | |
| 90 | /// getFileID - Return the file identifier for this SourceLocation. This |
| 91 | /// FileID can be used with the SourceManager object to obtain an entire |
| 92 | /// include stack for a file position reference. |
Chris Lattner | 9dc1f53 | 2007-07-20 16:37:10 +0000 | [diff] [blame] | 93 | unsigned getFileID() const { |
| 94 | assert(isFileID() && "can't get the file id of a non-file sloc!"); |
| 95 | return ID >> FilePosBits; |
| 96 | } |
Reid Spencer | 5f016e2 | 2007-07-11 17:01:13 +0000 | [diff] [blame] | 97 | |
| 98 | /// getRawFilePos - Return the byte offset from the start of the file-chunk |
| 99 | /// referred to by FileID. This method should not be used to get the offset |
| 100 | /// from the start of the file, instead you should use |
| 101 | /// SourceManager::getFilePos. This method will be incorrect for large files. |
Chris Lattner | 9dc1f53 | 2007-07-20 16:37:10 +0000 | [diff] [blame] | 102 | unsigned getRawFilePos() const { |
| 103 | assert(isFileID() && "can't get the file id of a non-file sloc!"); |
Chris Lattner | 2c64b7b | 2007-10-16 21:07:07 +0000 | [diff] [blame] | 104 | return ID & (ChunkSize-1); |
Chris Lattner | 9dc1f53 | 2007-07-20 16:37:10 +0000 | [diff] [blame] | 105 | } |
| 106 | |
| 107 | unsigned getMacroID() const { |
| 108 | assert(isMacroID() && "Is not a macro id!"); |
| 109 | return (ID >> (MacroPhysOffsBits+MacroLogOffBits)) & ((1 << MacroIDBits)-1); |
| 110 | } |
Reid Spencer | 5f016e2 | 2007-07-11 17:01:13 +0000 | [diff] [blame] | 111 | |
Chris Lattner | d1623a8 | 2007-07-21 06:41:57 +0000 | [diff] [blame] | 112 | int getMacroPhysOffs() const { |
Chris Lattner | 9dc1f53 | 2007-07-20 16:37:10 +0000 | [diff] [blame] | 113 | assert(isMacroID() && "Is not a macro id!"); |
Chris Lattner | d1623a8 | 2007-07-21 06:41:57 +0000 | [diff] [blame] | 114 | int Val = (ID >> MacroLogOffBits) & ((1 << MacroPhysOffsBits)-1); |
| 115 | // Sign extend it properly. |
| 116 | unsigned ShAmt = sizeof(int)*8 - MacroPhysOffsBits; |
| 117 | return (Val << ShAmt) >> ShAmt; |
Chris Lattner | 9dc1f53 | 2007-07-20 16:37:10 +0000 | [diff] [blame] | 118 | } |
| 119 | |
| 120 | unsigned getMacroLogOffs() const { |
| 121 | assert(isMacroID() && "Is not a macro id!"); |
Chris Lattner | 31bb8be | 2007-07-20 18:00:12 +0000 | [diff] [blame] | 122 | return ID & ((1 << MacroLogOffBits)-1); |
Chris Lattner | 9dc1f53 | 2007-07-20 16:37:10 +0000 | [diff] [blame] | 123 | } |
| 124 | |
| 125 | /// getFileLocWithOffset - Return a source location with the specified offset |
| 126 | /// from this file SourceLocation. |
Chris Lattner | d1623a8 | 2007-07-21 06:41:57 +0000 | [diff] [blame] | 127 | SourceLocation getFileLocWithOffset(int Offset) const { |
Chris Lattner | 2c64b7b | 2007-10-16 21:07:07 +0000 | [diff] [blame] | 128 | unsigned FileID = getFileID(); |
| 129 | Offset += getRawFilePos(); |
| 130 | // Handle negative offsets correctly. |
| 131 | while (Offset < 0) { |
| 132 | --FileID; |
| 133 | Offset += ChunkSize; |
| 134 | } |
| 135 | return getFileLoc(FileID, Offset); |
Chris Lattner | 9dc1f53 | 2007-07-20 16:37:10 +0000 | [diff] [blame] | 136 | } |
Reid Spencer | 5f016e2 | 2007-07-11 17:01:13 +0000 | [diff] [blame] | 137 | |
| 138 | /// getRawEncoding - When a SourceLocation itself cannot be used, this returns |
| 139 | /// an (opaque) 32-bit integer encoding for it. This should only be passed |
| 140 | /// to SourceLocation::getFromRawEncoding, it should not be inspected |
| 141 | /// directly. |
| 142 | unsigned getRawEncoding() const { return ID; } |
| 143 | |
| 144 | /// getFromRawEncoding - Turn a raw encoding of a SourceLocation object into |
| 145 | /// a real SourceLocation. |
| 146 | static SourceLocation getFromRawEncoding(unsigned Encoding) { |
| 147 | SourceLocation X; |
| 148 | X.ID = Encoding; |
| 149 | return X; |
| 150 | } |
| 151 | }; |
| 152 | |
| 153 | inline bool operator==(const SourceLocation &LHS, const SourceLocation &RHS) { |
| 154 | return LHS.getRawEncoding() == RHS.getRawEncoding(); |
| 155 | } |
| 156 | |
| 157 | inline bool operator!=(const SourceLocation &LHS, const SourceLocation &RHS) { |
| 158 | return !(LHS == RHS); |
| 159 | } |
| 160 | |
| 161 | /// SourceRange - a trival tuple used to represent a source range. |
| 162 | class SourceRange { |
| 163 | SourceLocation B; |
| 164 | SourceLocation E; |
| 165 | public: |
| 166 | SourceRange(): B(SourceLocation()), E(SourceLocation()) {} |
| 167 | SourceRange(SourceLocation loc) : B(loc), E(loc) {} |
| 168 | SourceRange(SourceLocation begin, SourceLocation end) : B(begin), E(end) {} |
| 169 | |
Chris Lattner | 311ff02 | 2007-10-16 22:36:42 +0000 | [diff] [blame] | 170 | SourceLocation getBegin() const { return B; } |
| 171 | SourceLocation getEnd() const { return E; } |
Reid Spencer | 5f016e2 | 2007-07-11 17:01:13 +0000 | [diff] [blame] | 172 | |
Chris Lattner | e80a59c | 2007-07-25 00:24:17 +0000 | [diff] [blame] | 173 | void setBegin(SourceLocation b) { B = b; } |
| 174 | void setEnd(SourceLocation e) { E = e; } |
| 175 | |
Reid Spencer | 5f016e2 | 2007-07-11 17:01:13 +0000 | [diff] [blame] | 176 | bool isValid() const { return B.isValid() && E.isValid(); } |
| 177 | }; |
| 178 | |
| 179 | } // end namespace clang |
| 180 | |
Ted Kremenek | 19a95bc | 2007-10-25 16:02:43 +0000 | [diff] [blame] | 181 | //===----------------------------------------------------------------------===// |
| 182 | // Serialization of SourceLocations and SourceRanges. |
| 183 | //===----------------------------------------------------------------------===// |
| 184 | |
| 185 | namespace llvm { |
| 186 | |
| 187 | template<> struct SerializeTrait<clang::SourceLocation> { |
| 188 | static void Emit(Serializer& S, clang::SourceLocation L); |
| 189 | static clang::SourceLocation ReadVal(Deserializer& D); |
| 190 | }; |
| 191 | |
| 192 | template<> struct SerializeTrait<clang::SourceRange> { |
| 193 | static inline void Emit(Serializer& S, clang::SourceRange R) { |
| 194 | SerializeTrait<clang::SourceLocation>::Emit(S,R.getBegin()); |
| 195 | SerializeTrait<clang::SourceLocation>::Emit(S,R.getEnd()); |
| 196 | } |
| 197 | |
| 198 | static inline clang::SourceRange ReadVal(Deserializer& D) { |
| 199 | using clang::SourceLocation; |
| 200 | SourceLocation L = SerializeTrait<SourceLocation>::ReadVal(D); |
| 201 | SourceLocation R = SerializeTrait<SourceLocation>::ReadVal(D); |
| 202 | return clang::SourceRange(L,R); |
| 203 | } |
| 204 | }; |
| 205 | |
| 206 | } // end namespace llvm |
| 207 | |
Reid Spencer | 5f016e2 | 2007-07-11 17:01:13 +0000 | [diff] [blame] | 208 | #endif |