|  | //===- SourceMgr.h - Manager for Source Buffers & Diagnostics ---*- C++ -*-===// | 
|  | // | 
|  | //                     The LLVM Compiler Infrastructure | 
|  | // | 
|  | // This file is distributed under the University of Illinois Open Source | 
|  | // License. See LICENSE.TXT for details. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | // This file declares the SMDiagnostic and SourceMgr classes.  This | 
|  | // provides a simple substrate for diagnostics, #include handling, and other low | 
|  | // level things for simple parsers. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #ifndef LLVM_SUPPORT_SOURCEMGR_H | 
|  | #define LLVM_SUPPORT_SOURCEMGR_H | 
|  |  | 
|  | #include "llvm/ADT/ArrayRef.h" | 
|  | #include "llvm/ADT/StringRef.h" | 
|  | #include "llvm/ADT/Twine.h" | 
|  | #include "llvm/Support/MemoryBuffer.h" | 
|  | #include "llvm/Support/SMLoc.h" | 
|  | #include <string> | 
|  |  | 
|  | namespace llvm { | 
|  | class SourceMgr; | 
|  | class SMDiagnostic; | 
|  | class SMFixIt; | 
|  | class Twine; | 
|  | class raw_ostream; | 
|  |  | 
|  | /// This owns the files read by a parser, handles include stacks, | 
|  | /// and handles diagnostic wrangling. | 
|  | class SourceMgr { | 
|  | public: | 
|  | enum DiagKind { | 
|  | DK_Error, | 
|  | DK_Warning, | 
|  | DK_Note | 
|  | }; | 
|  |  | 
|  | /// Clients that want to handle their own diagnostics in a custom way can | 
|  | /// register a function pointer+context as a diagnostic handler. | 
|  | /// It gets called each time PrintMessage is invoked. | 
|  | typedef void (*DiagHandlerTy)(const SMDiagnostic &, void *Context); | 
|  | private: | 
|  | struct SrcBuffer { | 
|  | /// The memory buffer for the file. | 
|  | std::unique_ptr<MemoryBuffer> Buffer; | 
|  |  | 
|  | /// This is the location of the parent include, or null if at the top level. | 
|  | SMLoc IncludeLoc; | 
|  | }; | 
|  |  | 
|  | /// This is all of the buffers that we are reading from. | 
|  | std::vector<SrcBuffer> Buffers; | 
|  |  | 
|  | // This is the list of directories we should search for include files in. | 
|  | std::vector<std::string> IncludeDirectories; | 
|  |  | 
|  | /// This is a cache for line number queries, its implementation is really | 
|  | /// private to SourceMgr.cpp. | 
|  | mutable void *LineNoCache; | 
|  |  | 
|  | DiagHandlerTy DiagHandler; | 
|  | void *DiagContext; | 
|  |  | 
|  | bool isValidBufferID(unsigned i) const { return i && i <= Buffers.size(); } | 
|  |  | 
|  | SourceMgr(const SourceMgr&) = delete; | 
|  | void operator=(const SourceMgr&) = delete; | 
|  | public: | 
|  | SourceMgr() | 
|  | : LineNoCache(nullptr), DiagHandler(nullptr), DiagContext(nullptr) {} | 
|  | ~SourceMgr(); | 
|  |  | 
|  | void setIncludeDirs(const std::vector<std::string> &Dirs) { | 
|  | IncludeDirectories = Dirs; | 
|  | } | 
|  |  | 
|  | /// Specify a diagnostic handler to be invoked every time PrintMessage is | 
|  | /// called. \p Ctx is passed into the handler when it is invoked. | 
|  | void setDiagHandler(DiagHandlerTy DH, void *Ctx = nullptr) { | 
|  | DiagHandler = DH; | 
|  | DiagContext = Ctx; | 
|  | } | 
|  |  | 
|  | DiagHandlerTy getDiagHandler() const { return DiagHandler; } | 
|  | void *getDiagContext() const { return DiagContext; } | 
|  |  | 
|  | const SrcBuffer &getBufferInfo(unsigned i) const { | 
|  | assert(isValidBufferID(i)); | 
|  | return Buffers[i - 1]; | 
|  | } | 
|  |  | 
|  | const MemoryBuffer *getMemoryBuffer(unsigned i) const { | 
|  | assert(isValidBufferID(i)); | 
|  | return Buffers[i - 1].Buffer.get(); | 
|  | } | 
|  |  | 
|  | unsigned getNumBuffers() const { | 
|  | return Buffers.size(); | 
|  | } | 
|  |  | 
|  | unsigned getMainFileID() const { | 
|  | assert(getNumBuffers()); | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | SMLoc getParentIncludeLoc(unsigned i) const { | 
|  | assert(isValidBufferID(i)); | 
|  | return Buffers[i - 1].IncludeLoc; | 
|  | } | 
|  |  | 
|  | /// Add a new source buffer to this source manager. This takes ownership of | 
|  | /// the memory buffer. | 
|  | unsigned AddNewSourceBuffer(std::unique_ptr<MemoryBuffer> F, | 
|  | SMLoc IncludeLoc) { | 
|  | SrcBuffer NB; | 
|  | NB.Buffer = std::move(F); | 
|  | NB.IncludeLoc = IncludeLoc; | 
|  | Buffers.push_back(std::move(NB)); | 
|  | return Buffers.size(); | 
|  | } | 
|  |  | 
|  | /// Search for a file with the specified name in the current directory or in | 
|  | /// one of the IncludeDirs. | 
|  | /// | 
|  | /// If no file is found, this returns 0, otherwise it returns the buffer ID | 
|  | /// of the stacked file. The full path to the included file can be found in | 
|  | /// \p IncludedFile. | 
|  | unsigned AddIncludeFile(const std::string &Filename, SMLoc IncludeLoc, | 
|  | std::string &IncludedFile); | 
|  |  | 
|  | /// Return the ID of the buffer containing the specified location. | 
|  | /// | 
|  | /// 0 is returned if the buffer is not found. | 
|  | unsigned FindBufferContainingLoc(SMLoc Loc) const; | 
|  |  | 
|  | /// Find the line number for the specified location in the specified file. | 
|  | /// This is not a fast method. | 
|  | unsigned FindLineNumber(SMLoc Loc, unsigned BufferID = 0) const { | 
|  | return getLineAndColumn(Loc, BufferID).first; | 
|  | } | 
|  |  | 
|  | /// Find the line and column number for the specified location in the | 
|  | /// specified file. This is not a fast method. | 
|  | std::pair<unsigned, unsigned> getLineAndColumn(SMLoc Loc, | 
|  | unsigned BufferID = 0) const; | 
|  |  | 
|  | /// Emit a message about the specified location with the specified string. | 
|  | /// | 
|  | /// \param ShowColors Display colored messages if output is a terminal and | 
|  | /// the default error handler is used. | 
|  | void PrintMessage(raw_ostream &OS, SMLoc Loc, DiagKind Kind, | 
|  | const Twine &Msg, | 
|  | ArrayRef<SMRange> Ranges = None, | 
|  | ArrayRef<SMFixIt> FixIts = None, | 
|  | bool ShowColors = true) const; | 
|  |  | 
|  | /// Emits a diagnostic to llvm::errs(). | 
|  | void PrintMessage(SMLoc Loc, DiagKind Kind, const Twine &Msg, | 
|  | ArrayRef<SMRange> Ranges = None, | 
|  | ArrayRef<SMFixIt> FixIts = None, | 
|  | bool ShowColors = true) const; | 
|  |  | 
|  | /// Emits a manually-constructed diagnostic to the given output stream. | 
|  | /// | 
|  | /// \param ShowColors Display colored messages if output is a terminal and | 
|  | /// the default error handler is used. | 
|  | void PrintMessage(raw_ostream &OS, const SMDiagnostic &Diagnostic, | 
|  | bool ShowColors = true) const; | 
|  |  | 
|  | /// Return an SMDiagnostic at the specified location with the specified | 
|  | /// string. | 
|  | /// | 
|  | /// \param Msg If non-null, the kind of message (e.g., "error") which is | 
|  | /// prefixed to the message. | 
|  | SMDiagnostic GetMessage(SMLoc Loc, DiagKind Kind, const Twine &Msg, | 
|  | ArrayRef<SMRange> Ranges = None, | 
|  | ArrayRef<SMFixIt> FixIts = None) const; | 
|  |  | 
|  | /// Prints the names of included files and the line of the file they were | 
|  | /// included from. A diagnostic handler can use this before printing its | 
|  | /// custom formatted message. | 
|  | /// | 
|  | /// \param IncludeLoc The location of the include. | 
|  | /// \param OS the raw_ostream to print on. | 
|  | void PrintIncludeStack(SMLoc IncludeLoc, raw_ostream &OS) const; | 
|  | }; | 
|  |  | 
|  |  | 
|  | /// Represents a single fixit, a replacement of one range of text with another. | 
|  | class SMFixIt { | 
|  | SMRange Range; | 
|  |  | 
|  | std::string Text; | 
|  |  | 
|  | public: | 
|  | // FIXME: Twine.str() is not very efficient. | 
|  | SMFixIt(SMLoc Loc, const Twine &Insertion) | 
|  | : Range(Loc, Loc), Text(Insertion.str()) { | 
|  | assert(Loc.isValid()); | 
|  | } | 
|  |  | 
|  | // FIXME: Twine.str() is not very efficient. | 
|  | SMFixIt(SMRange R, const Twine &Replacement) | 
|  | : Range(R), Text(Replacement.str()) { | 
|  | assert(R.isValid()); | 
|  | } | 
|  |  | 
|  | StringRef getText() const { return Text; } | 
|  | SMRange getRange() const { return Range; } | 
|  |  | 
|  | bool operator<(const SMFixIt &Other) const { | 
|  | if (Range.Start.getPointer() != Other.Range.Start.getPointer()) | 
|  | return Range.Start.getPointer() < Other.Range.Start.getPointer(); | 
|  | if (Range.End.getPointer() != Other.Range.End.getPointer()) | 
|  | return Range.End.getPointer() < Other.Range.End.getPointer(); | 
|  | return Text < Other.Text; | 
|  | } | 
|  | }; | 
|  |  | 
|  |  | 
|  | /// Instances of this class encapsulate one diagnostic report, allowing | 
|  | /// printing to a raw_ostream as a caret diagnostic. | 
|  | class SMDiagnostic { | 
|  | const SourceMgr *SM; | 
|  | SMLoc Loc; | 
|  | std::string Filename; | 
|  | int LineNo, ColumnNo; | 
|  | SourceMgr::DiagKind Kind; | 
|  | std::string Message, LineContents; | 
|  | std::vector<std::pair<unsigned, unsigned> > Ranges; | 
|  | SmallVector<SMFixIt, 4> FixIts; | 
|  |  | 
|  | public: | 
|  | // Null diagnostic. | 
|  | SMDiagnostic() | 
|  | : SM(nullptr), LineNo(0), ColumnNo(0), Kind(SourceMgr::DK_Error) {} | 
|  | // Diagnostic with no location (e.g. file not found, command line arg error). | 
|  | SMDiagnostic(StringRef filename, SourceMgr::DiagKind Knd, StringRef Msg) | 
|  | : SM(nullptr), Filename(filename), LineNo(-1), ColumnNo(-1), Kind(Knd), | 
|  | Message(Msg) {} | 
|  |  | 
|  | // Diagnostic with a location. | 
|  | SMDiagnostic(const SourceMgr &sm, SMLoc L, StringRef FN, | 
|  | int Line, int Col, SourceMgr::DiagKind Kind, | 
|  | StringRef Msg, StringRef LineStr, | 
|  | ArrayRef<std::pair<unsigned,unsigned> > Ranges, | 
|  | ArrayRef<SMFixIt> FixIts = None); | 
|  |  | 
|  | const SourceMgr *getSourceMgr() const { return SM; } | 
|  | SMLoc getLoc() const { return Loc; } | 
|  | StringRef getFilename() const { return Filename; } | 
|  | int getLineNo() const { return LineNo; } | 
|  | int getColumnNo() const { return ColumnNo; } | 
|  | SourceMgr::DiagKind getKind() const { return Kind; } | 
|  | StringRef getMessage() const { return Message; } | 
|  | StringRef getLineContents() const { return LineContents; } | 
|  | ArrayRef<std::pair<unsigned, unsigned> > getRanges() const { | 
|  | return Ranges; | 
|  | } | 
|  |  | 
|  | void addFixIt(const SMFixIt &Hint) { | 
|  | FixIts.push_back(Hint); | 
|  | } | 
|  |  | 
|  | ArrayRef<SMFixIt> getFixIts() const { | 
|  | return FixIts; | 
|  | } | 
|  |  | 
|  | void print(const char *ProgName, raw_ostream &S, bool ShowColors = true, | 
|  | bool ShowKindLabel = true) const; | 
|  | }; | 
|  |  | 
|  | }  // end llvm namespace | 
|  |  | 
|  | #endif |