Home | History | Annotate | Download | only in Support
      1 //===- SourceMgr.h - Manager for Source Buffers & Diagnostics ---*- C++ -*-===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // This file declares the SMDiagnostic and SourceMgr classes.  This
     11 // provides a simple substrate for diagnostics, #include handling, and other low
     12 // level things for simple parsers.
     13 //
     14 //===----------------------------------------------------------------------===//
     15 
     16 #ifndef LLVM_SUPPORT_SOURCEMGR_H
     17 #define LLVM_SUPPORT_SOURCEMGR_H
     18 
     19 #include "llvm/ADT/ArrayRef.h"
     20 #include "llvm/ADT/StringRef.h"
     21 #include "llvm/ADT/Twine.h"
     22 #include "llvm/Support/SMLoc.h"
     23 #include <string>
     24 
     25 namespace llvm {
     26   class MemoryBuffer;
     27   class SourceMgr;
     28   class SMDiagnostic;
     29   class SMFixIt;
     30   class Twine;
     31   class raw_ostream;
     32 
     33 /// SourceMgr - This owns the files read by a parser, handles include stacks,
     34 /// and handles diagnostic wrangling.
     35 class SourceMgr {
     36 public:
     37   enum DiagKind {
     38     DK_Error,
     39     DK_Warning,
     40     DK_Note
     41   };
     42 
     43   /// DiagHandlerTy - Clients that want to handle their own diagnostics in a
     44   /// custom way can register a function pointer+context as a diagnostic
     45   /// handler.  It gets called each time PrintMessage is invoked.
     46   typedef void (*DiagHandlerTy)(const SMDiagnostic &, void *Context);
     47 private:
     48   struct SrcBuffer {
     49     /// Buffer - The memory buffer for the file.
     50     MemoryBuffer *Buffer;
     51 
     52     /// IncludeLoc - This is the location of the parent include, or null if at
     53     /// the top level.
     54     SMLoc IncludeLoc;
     55   };
     56 
     57   /// Buffers - This is all of the buffers that we are reading from.
     58   std::vector<SrcBuffer> Buffers;
     59 
     60   // IncludeDirectories - This is the list of directories we should search for
     61   // include files in.
     62   std::vector<std::string> IncludeDirectories;
     63 
     64   /// LineNoCache - This is a cache for line number queries, its implementation
     65   /// is really private to SourceMgr.cpp.
     66   mutable void *LineNoCache;
     67 
     68   DiagHandlerTy DiagHandler;
     69   void *DiagContext;
     70 
     71   SourceMgr(const SourceMgr&) LLVM_DELETED_FUNCTION;
     72   void operator=(const SourceMgr&) LLVM_DELETED_FUNCTION;
     73 public:
     74   SourceMgr() : LineNoCache(0), DiagHandler(0), DiagContext(0) {}
     75   ~SourceMgr();
     76 
     77   void setIncludeDirs(const std::vector<std::string> &Dirs) {
     78     IncludeDirectories = Dirs;
     79   }
     80 
     81   /// setDiagHandler - Specify a diagnostic handler to be invoked every time
     82   /// PrintMessage is called. Ctx is passed into the handler when it is invoked.
     83   void setDiagHandler(DiagHandlerTy DH, void *Ctx = 0) {
     84     DiagHandler = DH;
     85     DiagContext = Ctx;
     86   }
     87 
     88   DiagHandlerTy getDiagHandler() const { return DiagHandler; }
     89   void *getDiagContext() const { return DiagContext; }
     90 
     91   const SrcBuffer &getBufferInfo(unsigned i) const {
     92     assert(i < Buffers.size() && "Invalid Buffer ID!");
     93     return Buffers[i];
     94   }
     95 
     96   const MemoryBuffer *getMemoryBuffer(unsigned i) const {
     97     assert(i < Buffers.size() && "Invalid Buffer ID!");
     98     return Buffers[i].Buffer;
     99   }
    100 
    101   unsigned getNumBuffers() const {
    102     return Buffers.size();
    103   }
    104 
    105   SMLoc getParentIncludeLoc(unsigned i) const {
    106     assert(i < Buffers.size() && "Invalid Buffer ID!");
    107     return Buffers[i].IncludeLoc;
    108   }
    109 
    110   /// AddNewSourceBuffer - Add a new source buffer to this source manager.  This
    111   /// takes ownership of the memory buffer.
    112   unsigned AddNewSourceBuffer(MemoryBuffer *F, SMLoc IncludeLoc) {
    113     SrcBuffer NB;
    114     NB.Buffer = F;
    115     NB.IncludeLoc = IncludeLoc;
    116     Buffers.push_back(NB);
    117     return Buffers.size()-1;
    118   }
    119 
    120   /// AddIncludeFile - Search for a file with the specified name in the current
    121   /// directory or in one of the IncludeDirs.  If no file is found, this returns
    122   /// ~0, otherwise it returns the buffer ID of the stacked file.
    123   /// The full path to the included file can be found in IncludedFile.
    124   unsigned AddIncludeFile(const std::string &Filename, SMLoc IncludeLoc,
    125                           std::string &IncludedFile);
    126 
    127   /// FindBufferContainingLoc - Return the ID of the buffer containing the
    128   /// specified location, returning -1 if not found.
    129   int FindBufferContainingLoc(SMLoc Loc) const;
    130 
    131   /// FindLineNumber - Find the line number for the specified location in the
    132   /// specified file.  This is not a fast method.
    133   unsigned FindLineNumber(SMLoc Loc, int BufferID = -1) const {
    134     return getLineAndColumn(Loc, BufferID).first;
    135   }
    136 
    137   /// getLineAndColumn - Find the line and column number for the specified
    138   /// location in the specified file.  This is not a fast method.
    139   std::pair<unsigned, unsigned>
    140     getLineAndColumn(SMLoc Loc, int BufferID = -1) const;
    141 
    142   /// PrintMessage - Emit a message about the specified location with the
    143   /// specified string.
    144   ///
    145   /// @param ShowColors - Display colored messages if output is a terminal and
    146   /// the default error handler is used.
    147   void PrintMessage(SMLoc Loc, DiagKind Kind, const Twine &Msg,
    148                     ArrayRef<SMRange> Ranges = ArrayRef<SMRange>(),
    149                     ArrayRef<SMFixIt> FixIts = ArrayRef<SMFixIt>(),
    150                     bool ShowColors = true) const;
    151 
    152 
    153   /// GetMessage - Return an SMDiagnostic at the specified location with the
    154   /// specified string.
    155   ///
    156   /// @param Msg If non-null, the kind of message (e.g., "error") which is
    157   /// prefixed to the message.
    158   SMDiagnostic GetMessage(SMLoc Loc, DiagKind Kind, const Twine &Msg,
    159                           ArrayRef<SMRange> Ranges = ArrayRef<SMRange>(),
    160                           ArrayRef<SMFixIt> FixIts = ArrayRef<SMFixIt>()) const;
    161 
    162   /// PrintIncludeStack - Prints the names of included files and the line of the
    163   /// file they were included from.  A diagnostic handler can use this before
    164   /// printing its custom formatted message.
    165   ///
    166   /// @param IncludeLoc - The line of the include.
    167   /// @param OS the raw_ostream to print on.
    168   void PrintIncludeStack(SMLoc IncludeLoc, raw_ostream &OS) const;
    169 };
    170 
    171 
    172 /// Represents a single fixit, a replacement of one range of text with another.
    173 class SMFixIt {
    174   SMRange Range;
    175 
    176   std::string Text;
    177 
    178 public:
    179   // FIXME: Twine.str() is not very efficient.
    180   SMFixIt(SMLoc Loc, const Twine &Insertion)
    181     : Range(Loc, Loc), Text(Insertion.str()) {
    182     assert(Loc.isValid());
    183   }
    184 
    185   // FIXME: Twine.str() is not very efficient.
    186   SMFixIt(SMRange R, const Twine &Replacement)
    187     : Range(R), Text(Replacement.str()) {
    188     assert(R.isValid());
    189   }
    190 
    191   StringRef getText() const { return Text; }
    192   SMRange getRange() const { return Range; }
    193 
    194   bool operator<(const SMFixIt &Other) const {
    195     if (Range.Start.getPointer() != Other.Range.Start.getPointer())
    196       return Range.Start.getPointer() < Other.Range.Start.getPointer();
    197     if (Range.End.getPointer() != Other.Range.End.getPointer())
    198       return Range.End.getPointer() < Other.Range.End.getPointer();
    199     return Text < Other.Text;
    200   }
    201 };
    202 
    203 
    204 /// SMDiagnostic - Instances of this class encapsulate one diagnostic report,
    205 /// allowing printing to a raw_ostream as a caret diagnostic.
    206 class SMDiagnostic {
    207   const SourceMgr *SM;
    208   SMLoc Loc;
    209   std::string Filename;
    210   int LineNo, ColumnNo;
    211   SourceMgr::DiagKind Kind;
    212   std::string Message, LineContents;
    213   std::vector<std::pair<unsigned, unsigned> > Ranges;
    214   SmallVector<SMFixIt, 4> FixIts;
    215 
    216 public:
    217   // Null diagnostic.
    218   SMDiagnostic()
    219     : SM(0), LineNo(0), ColumnNo(0), Kind(SourceMgr::DK_Error) {}
    220   // Diagnostic with no location (e.g. file not found, command line arg error).
    221   SMDiagnostic(StringRef filename, SourceMgr::DiagKind Knd, StringRef Msg)
    222     : SM(0), Filename(filename), LineNo(-1), ColumnNo(-1), Kind(Knd),
    223       Message(Msg) {}
    224 
    225   // Diagnostic with a location.
    226   SMDiagnostic(const SourceMgr &sm, SMLoc L, StringRef FN,
    227                int Line, int Col, SourceMgr::DiagKind Kind,
    228                StringRef Msg, StringRef LineStr,
    229                ArrayRef<std::pair<unsigned,unsigned> > Ranges,
    230                ArrayRef<SMFixIt> FixIts = ArrayRef<SMFixIt>());
    231 
    232   const SourceMgr *getSourceMgr() const { return SM; }
    233   SMLoc getLoc() const { return Loc; }
    234   StringRef getFilename() const { return Filename; }
    235   int getLineNo() const { return LineNo; }
    236   int getColumnNo() const { return ColumnNo; }
    237   SourceMgr::DiagKind getKind() const { return Kind; }
    238   StringRef getMessage() const { return Message; }
    239   StringRef getLineContents() const { return LineContents; }
    240   ArrayRef<std::pair<unsigned, unsigned> > getRanges() const {
    241     return Ranges;
    242   }
    243 
    244   void addFixIt(const SMFixIt &Hint) {
    245     FixIts.push_back(Hint);
    246   }
    247 
    248   ArrayRef<SMFixIt> getFixIts() const {
    249     return FixIts;
    250   }
    251 
    252   void print(const char *ProgName, raw_ostream &S,
    253              bool ShowColors = true) const;
    254 };
    255 
    256 }  // end llvm namespace
    257 
    258 #endif
    259