blob: ef0ac0ba981915e0b04f79db4bb38d351ce43b09 [file] [log] [blame]
//===--- 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>
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::FileIDInfo *FIDInfo) const {
// For Macros, the physical loc is specified by the MacroTokenFileID.
if (FIDInfo->IDType == SrcMgr::FileIDInfo::MacroExpansion)
FIDInfo = &FileIDs[FIDInfo->u.MacroTokenFileID-1];
return FIDInfo->getNormalBufferInfo();
}
const SrcMgr::InfoRec *getInfoRec(unsigned FileID) const {
return getInfoRec(getFIDInfo(FileID));
}
SrcMgr::FileInfo *getFileInfo(const SrcMgr::FileIDInfo *FIDInfo) const {
if (const SrcMgr::InfoRec *IR = getInfoRec(FIDInfo))
return const_cast<SrcMgr::FileInfo *>(&IR->second);
return 0;
}
SrcMgr::FileInfo *getFileInfo(unsigned FileID) const {
if (const SrcMgr::InfoRec *IR = getInfoRec(FileID))
return const_cast<SrcMgr::FileInfo *>(&IR->second);
return 0;
}
SrcMgr::FileInfo *getFileInfo(const FileEntry *SourceFile) {
if (const SrcMgr::InfoRec *IR = getInfoRec(SourceFile))
return const_cast<SrcMgr::FileInfo *>(&IR->second);
return 0;
}
};
} // end namespace clang
#endif