//===--- 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 #include #include #include 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 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 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 MemBufferInfos; /// FileIDs - Information about each FileID. FileID #0 is not valid, so all /// entries are off by one. std::vector 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(&IR->second); return 0; } SrcMgr::FileInfo *getFileInfo(unsigned FileID) const { if (const SrcMgr::InfoRec *IR = getInfoRec(FileID)) return const_cast(&IR->second); return 0; } SrcMgr::FileInfo *getFileInfo(const FileEntry *SourceFile) { if (const SrcMgr::InfoRec *IR = getInfoRec(SourceFile)) return const_cast(&IR->second); return 0; } }; } // end namespace clang #endif