aboutsummaryrefslogtreecommitdiff
path: root/include/clang/Basic/SourceManager.h
blob: e7f0d30a1fadf3b38e9b035a0ddd0987bb1d5d1a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
//===--- SourceManager.h - Track and cache source files ---------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by Chris Lattner and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file defines the SourceManager interface.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_SOURCEMANAGER_H
#define LLVM_CLANG_SOURCEMANAGER_H

#include "clang/Basic/SourceLocation.h"
#include <vector>
#include <map>
#include <list>
#include <cassert>

namespace llvm {
class MemoryBuffer;
}
  
namespace clang {
  
class SourceManager;
class FileEntry;
class IdentifierTokenInfo;

/// SrcMgr - Private classes that are part of the SourceManager implementation.
///
namespace SrcMgr {
  /// FileInfo - Once instance of this struct is kept for every file loaded or
  /// used.  This object owns the MemoryBuffer object.
  struct FileInfo {
    /// Buffer - The actual buffer containing the characters from the input
    /// file.
    const llvm::MemoryBuffer *Buffer;
    
    /// SourceLineCache - A new[]'d array of offsets for each source line.  This
    /// is lazily computed.
    ///
    unsigned *SourceLineCache;
    
    /// NumLines - The number of lines in this FileInfo.  This is only valid if
    /// SourceLineCache is non-null.
    unsigned NumLines;
  };
  
  typedef std::pair<const FileEntry * const, FileInfo> InfoRec;

  /// FileIDInfo - Information about a FileID, basically just the logical file
  /// that it represents and include stack information.  A SourceLocation is a
  /// byte offset from the start of this.
  ///
  /// FileID's are used to compute the location of a character in memory as well
  /// as the logical source location, which can be differ from the physical
  /// location.  It is different when #line's are active or when macros have
  /// been expanded.
  ///
  /// Each FileID has include stack information, indicating where it came from.
  /// For the primary translation unit, it comes from SourceLocation() aka 0.
  ///
  /// There are three types of FileID's:
  ///   1. Normal MemoryBuffer (file).  These are represented by a "InfoRec *",
  ///      describing the source file, and a Chunk number, which factors into
  ///      the SourceLocation's offset from the start of the buffer.
  ///   2. Macro Expansions.  These indicate that the logical location is
  ///      totally different than the physical location.  The logical source
  ///      location is specified by the IncludeLoc.  The physical location is
  ///      the FilePos of the token's SourceLocation combined with the FileID
  ///      from MacroTokenFileID.
  ///
  struct FileIDInfo {
    enum FileIDType {
      NormalBuffer,
      MacroExpansion
    };
    
    /// The type of this FileID.
    FileIDType IDType;
    
    /// IncludeLoc - The location of the #include that brought in this file.
    /// This SourceLocation object has a FileId of 0 for the main file.
    SourceLocation IncludeLoc;
    
    /// This union is discriminated by IDType.
    ///
    union {
      struct NormalBufferInfo {
        /// ChunkNo - Really large buffers are broken up into chunks that are
        /// each (1 << SourceLocation::FilePosBits) in size.  This specifies the
        /// chunk number of this FileID.
        unsigned ChunkNo;
        
        /// FileInfo - Information about the source buffer itself.
        ///
        const InfoRec *Info;
      } NormalBuffer;
      
      /// MacroTokenFileID - This is the File ID that contains the characters
      /// that make up the expanded token.
      unsigned MacroTokenFileID;
    } u;
    
    /// getNormalBuffer - Return a FileIDInfo object for a normal buffer
    /// reference.
    static FileIDInfo getNormalBuffer(SourceLocation IL, unsigned CN,
                                      const InfoRec *Inf) {
      FileIDInfo X;
      X.IDType = NormalBuffer;
      X.IncludeLoc = IL;
      X.u.NormalBuffer.ChunkNo = CN;
      X.u.NormalBuffer.Info = Inf;
      return X;
    }
    
    /// getMacroExpansion - Return a FileID for a macro expansion.  IL specifies
    /// the instantiation location, and MacroFID specifies the FileID that the
    /// token's characters come from. 
    static FileIDInfo getMacroExpansion(SourceLocation IL,
                                        unsigned MacroFID) {
      FileIDInfo X;
      X.IDType = MacroExpansion;
      X.IncludeLoc = IL;
      X.u.MacroTokenFileID = MacroFID;
      return X;
    }
    
    unsigned getNormalBufferChunkNo() const {
      assert(IDType == NormalBuffer && "Not a normal buffer!");
      return u.NormalBuffer.ChunkNo;
    }

    const InfoRec *getNormalBufferInfo() const {
      assert(IDType == NormalBuffer && "Not a normal buffer!");
      return u.NormalBuffer.Info;
    }
  };
}  // end SrcMgr namespace.


/// SourceManager - This file handles loading and caching of source files into
/// memory.  This object owns the MemoryBuffer objects for all of the loaded
/// files and assigns unique FileID's for each unique #include chain.
///
/// The SourceManager can be queried for information about SourceLocation
/// objects, turning them into either physical or logical locations.  Physical
/// locations represent where the bytes corresponding to a token came from and
/// logical locations represent where the location is in the user's view.  In
/// the case of a macro expansion, for example, the physical location indicates
/// where the expanded token came from and the logical location specifies where
/// it was expanded.  Logical locations are also influenced by #line directives,
/// etc.
class SourceManager {
  /// FileInfos - Memoized information about all of the files tracked by this
  /// SourceManager.
  std::map<const FileEntry *, SrcMgr::FileInfo> FileInfos;
  
  /// MemBufferInfos - Information about various memory buffers that we have
  /// read in.  This is a list, instead of a vector, because we need pointers to
  /// the FileInfo objects to be stable.
  std::list<SrcMgr::InfoRec> MemBufferInfos;
  
  /// FileIDs - Information about each FileID.  FileID #0 is not valid, so all
  /// entries are off by one.
  std::vector<SrcMgr::FileIDInfo> FileIDs;
  
  /// LastInstantiationLoc_* - Cache the last instantiation request for fast
  /// lookup.  Macros often want many tokens instantated at the same location.
  SourceLocation LastInstantiationLoc_InstantLoc;
  unsigned       LastInstantiationLoc_MacroFID;
  unsigned       LastInstantiationLoc_Result;
public:
  SourceManager() { LastInstantiationLoc_MacroFID = ~0U; }
  ~SourceManager();
  
  /// createFileID - Create a new FileID that represents the specified file
  /// being #included from the specified IncludePosition.  This returns 0 on
  /// error and translates NULL into standard input.
  unsigned createFileID(const FileEntry *SourceFile, SourceLocation IncludePos){
    const SrcMgr::InfoRec *IR = getInfoRec(SourceFile);
    if (IR == 0) return 0;    // Error opening file?
    return createFileID(IR, IncludePos);
  }
  
  /// createFileIDForMemBuffer - Create a new FileID that represents the
  /// specified memory buffer.  This does no caching of the buffer and takes
  /// ownership of the MemoryBuffer, so only pass a MemoryBuffer to this once.
  unsigned createFileIDForMemBuffer(const llvm::MemoryBuffer *Buffer) {
    return createFileID(createMemBufferInfoRec(Buffer), SourceLocation());
  }
  
  /// getInstantiationLoc - Return a new SourceLocation that encodes the fact
  /// that a token from physloc PhysLoc should actually be referenced from
  /// InstantiationLoc.
  SourceLocation getInstantiationLoc(SourceLocation PhysLoc,
                                     SourceLocation InstantiationLoc);
  
  /// getBuffer - Return the buffer for the specified FileID.
  ///
  const llvm::MemoryBuffer *getBuffer(unsigned FileID) const {
    return getFileInfo(FileID)->Buffer;
  }
  
  /// getIncludeLoc - Return the location of the #include for the specified
  /// FileID.
  SourceLocation getIncludeLoc(unsigned FileID) const;
  
  /// getFilePos - This (efficient) method returns the offset from the start of
  /// the file that the specified SourceLocation represents.  This returns the
  /// location of the physical character data, not the logical file position.
  unsigned getFilePos(SourceLocation Loc) const {
    const SrcMgr::FileIDInfo *FIDInfo = getFIDInfo(Loc.getFileID());

    // For Macros, the physical loc is specified by the MacroTokenFileID.
    if (FIDInfo->IDType == SrcMgr::FileIDInfo::MacroExpansion)
      FIDInfo = &FileIDs[FIDInfo->u.MacroTokenFileID-1];
    
    // If this file has been split up into chunks, factor in the chunk number
    // that the FileID references.
    unsigned ChunkNo = FIDInfo->getNormalBufferChunkNo();
    return Loc.getRawFilePos() + (ChunkNo << SourceLocation::FilePosBits);
  }
  
  /// getCharacterData - Return a pointer to the start of the specified location
  /// in the appropriate MemoryBuffer.
  const char *getCharacterData(SourceLocation SL) const;
  
  /// getColumnNumber - Return the column # for the specified include position.
  /// this is significantly cheaper to compute than the line number.  This
  /// returns zero if the column number isn't known.
  unsigned getColumnNumber(SourceLocation Loc) const;
  
  /// getLineNumber - Given a SourceLocation, return the physical line number
  /// for the position indicated.  This requires building and caching a table of
  /// line offsets for the MemoryBuffer, so this is not cheap: use only when
  /// about to emit a diagnostic.
  unsigned getLineNumber(SourceLocation Loc);
  
  /// getSourceFilePos - This method returns the *logical* offset from the start
  /// of the file that the specified SourceLocation represents.  This returns
  /// the location of the *logical* character data, not the physical file
  /// position.  In the case of macros, for example, this returns where the
  /// macro was instantiated, not where the characters for the macro can be
  /// found.
  unsigned getSourceFilePos(SourceLocation Loc) const;
    
  /// getSourceName - This method returns the name of the file or buffer that
  /// the SourceLocation specifies.  This can be modified with #line directives,
  /// etc.
  std::string getSourceName(SourceLocation Loc);

  /// getFileEntryForFileID - Return the FileEntry record for the specified
  /// FileID if one exists.
  const FileEntry *getFileEntryForFileID(unsigned FileID) const {
    assert(FileID-1 < FileIDs.size() && "Invalid FileID!");
    return FileIDs[FileID-1].getNormalBufferInfo()->first;
  }
  
  /// Given a SourceLocation object, return the logical location referenced by
  /// the ID.  This logical location is subject to #line directives, etc.
  SourceLocation getLogicalLoc(SourceLocation Loc) const {
    if (Loc.getFileID() == 0) return Loc;
    
    const SrcMgr::FileIDInfo *FIDInfo = getFIDInfo(Loc.getFileID());
    if (FIDInfo->IDType == SrcMgr::FileIDInfo::MacroExpansion)
      return FIDInfo->IncludeLoc;
    return Loc;
  }
  
  /// getPhysicalLoc - Given a SourceLocation object, return the physical
  /// location referenced by the ID.
  SourceLocation getPhysicalLoc(SourceLocation Loc) const {
    if (Loc.getFileID() == 0) return Loc;
    
    // For Macros, the physical loc is specified by the MacroTokenFileID.
    const SrcMgr::FileIDInfo *FIDInfo = getFIDInfo(Loc.getFileID());
    if (FIDInfo->IDType == SrcMgr::FileIDInfo::MacroExpansion)
      return SourceLocation(FIDInfo->u.MacroTokenFileID,
                            Loc.getRawFilePos());
    return Loc;
  }
  
  /// PrintStats - Print statistics to stderr.
  ///
  void PrintStats() const;
private:
  /// createFileID - Create a new fileID for the specified InfoRec and include
  /// position.  This works regardless of whether the InfoRec corresponds to a
  /// file or some other input source.
  unsigned createFileID(const SrcMgr::InfoRec *File, SourceLocation IncludePos);
    
  /// getInfoRec - Create or return a cached FileInfo for the specified file.
  /// This returns null on failure.
  const SrcMgr::InfoRec *getInfoRec(const FileEntry *SourceFile);
  
  /// createMemBufferInfoRec - Create a new info record for the specified memory
  /// buffer.  This does no caching.
  const SrcMgr::InfoRec *createMemBufferInfoRec(const llvm::MemoryBuffer *Buf);

  const SrcMgr::FileIDInfo *getFIDInfo(unsigned FileID) const {
    assert(FileID-1 < FileIDs.size() && "Invalid FileID!");
    return &FileIDs[FileID-1];
  }
    
  /// Return the InfoRec structure for the specified FileID.  This is always the
  /// physical reference for the ID.
  const SrcMgr::InfoRec *getInfoRec(const SrcMgr