LLVM API Documentation

SourceMgr.h
Go to the documentation of this file.
00001 //===- SourceMgr.h - Manager for Source Buffers & Diagnostics ---*- C++ -*-===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 // This file declares the SMDiagnostic and SourceMgr classes.  This
00011 // provides a simple substrate for diagnostics, #include handling, and other low
00012 // level things for simple parsers.
00013 //
00014 //===----------------------------------------------------------------------===//
00015 
00016 #ifndef LLVM_SUPPORT_SOURCEMGR_H
00017 #define LLVM_SUPPORT_SOURCEMGR_H
00018 
00019 #include "llvm/ADT/ArrayRef.h"
00020 #include "llvm/ADT/StringRef.h"
00021 #include "llvm/ADT/Twine.h"
00022 #include "llvm/Support/MemoryBuffer.h"
00023 #include "llvm/Support/SMLoc.h"
00024 #include <string>
00025 
00026 namespace llvm {
00027   class SourceMgr;
00028   class SMDiagnostic;
00029   class SMFixIt;
00030   class Twine;
00031   class raw_ostream;
00032 
00033 /// This owns the files read by a parser, handles include stacks,
00034 /// and handles diagnostic wrangling.
00035 class SourceMgr {
00036 public:
00037   enum DiagKind {
00038     DK_Error,
00039     DK_Warning,
00040     DK_Note
00041   };
00042 
00043   /// Clients that want to handle their own diagnostics in a custom way can
00044   /// register a function pointer+context as a diagnostic handler.
00045   /// It gets called each time PrintMessage is invoked.
00046   typedef void (*DiagHandlerTy)(const SMDiagnostic &, void *Context);
00047 private:
00048   struct SrcBuffer {
00049     /// The memory buffer for the file.
00050     std::unique_ptr<MemoryBuffer> Buffer;
00051 
00052     /// This is the location of the parent include, or null if at the top level.
00053     SMLoc IncludeLoc;
00054 
00055     SrcBuffer() {}
00056 
00057     SrcBuffer(SrcBuffer &&O)
00058         : Buffer(std::move(O.Buffer)), IncludeLoc(O.IncludeLoc) {}
00059   };
00060 
00061   /// This is all of the buffers that we are reading from.
00062   std::vector<SrcBuffer> Buffers;
00063 
00064   // This is the list of directories we should search for include files in.
00065   std::vector<std::string> IncludeDirectories;
00066 
00067   /// This is a cache for line number queries, its implementation is really
00068   /// private to SourceMgr.cpp.
00069   mutable void *LineNoCache;
00070 
00071   DiagHandlerTy DiagHandler;
00072   void *DiagContext;
00073 
00074   bool isValidBufferID(unsigned i) const { return i && i <= Buffers.size(); }
00075 
00076   SourceMgr(const SourceMgr&) LLVM_DELETED_FUNCTION;
00077   void operator=(const SourceMgr&) LLVM_DELETED_FUNCTION;
00078 public:
00079   SourceMgr()
00080     : LineNoCache(nullptr), DiagHandler(nullptr), DiagContext(nullptr) {}
00081   ~SourceMgr();
00082 
00083   void setIncludeDirs(const std::vector<std::string> &Dirs) {
00084     IncludeDirectories = Dirs;
00085   }
00086 
00087   /// Specify a diagnostic handler to be invoked every time PrintMessage is
00088   /// called. \p Ctx is passed into the handler when it is invoked.
00089   void setDiagHandler(DiagHandlerTy DH, void *Ctx = nullptr) {
00090     DiagHandler = DH;
00091     DiagContext = Ctx;
00092   }
00093 
00094   DiagHandlerTy getDiagHandler() const { return DiagHandler; }
00095   void *getDiagContext() const { return DiagContext; }
00096 
00097   const SrcBuffer &getBufferInfo(unsigned i) const {
00098     assert(isValidBufferID(i));
00099     return Buffers[i - 1];
00100   }
00101 
00102   const MemoryBuffer *getMemoryBuffer(unsigned i) const {
00103     assert(isValidBufferID(i));
00104     return Buffers[i - 1].Buffer.get();
00105   }
00106 
00107   unsigned getNumBuffers() const {
00108     return Buffers.size();
00109   }
00110 
00111   unsigned getMainFileID() const {
00112     assert(getNumBuffers());
00113     return 1;
00114   }
00115 
00116   SMLoc getParentIncludeLoc(unsigned i) const {
00117     assert(isValidBufferID(i));
00118     return Buffers[i - 1].IncludeLoc;
00119   }
00120 
00121   /// Add a new source buffer to this source manager. This takes ownership of
00122   /// the memory buffer.
00123   unsigned AddNewSourceBuffer(std::unique_ptr<MemoryBuffer> F,
00124                               SMLoc IncludeLoc) {
00125     SrcBuffer NB;
00126     NB.Buffer = std::move(F);
00127     NB.IncludeLoc = IncludeLoc;
00128     Buffers.push_back(std::move(NB));
00129     return Buffers.size();
00130   }
00131 
00132   /// Search for a file with the specified name in the current directory or in
00133   /// one of the IncludeDirs.
00134   ///
00135   /// If no file is found, this returns 0, otherwise it returns the buffer ID
00136   /// of the stacked file. The full path to the included file can be found in
00137   /// \p IncludedFile.
00138   unsigned AddIncludeFile(const std::string &Filename, SMLoc IncludeLoc,
00139                           std::string &IncludedFile);
00140 
00141   /// Return the ID of the buffer containing the specified location.
00142   ///
00143   /// 0 is returned if the buffer is not found.
00144   unsigned FindBufferContainingLoc(SMLoc Loc) const;
00145 
00146   /// Find the line number for the specified location in the specified file.
00147   /// This is not a fast method.
00148   unsigned FindLineNumber(SMLoc Loc, unsigned BufferID = 0) const {
00149     return getLineAndColumn(Loc, BufferID).first;
00150   }
00151 
00152   /// Find the line and column number for the specified location in the
00153   /// specified file. This is not a fast method.
00154   std::pair<unsigned, unsigned> getLineAndColumn(SMLoc Loc,
00155                                                  unsigned BufferID = 0) const;
00156 
00157   /// Emit a message about the specified location with the specified string.
00158   ///
00159   /// \param ShowColors Display colored messages if output is a terminal and
00160   /// the default error handler is used.
00161   void PrintMessage(raw_ostream &OS, SMLoc Loc, DiagKind Kind,
00162                     const Twine &Msg,
00163                     ArrayRef<SMRange> Ranges = None,
00164                     ArrayRef<SMFixIt> FixIts = None,
00165                     bool ShowColors = true) const;
00166 
00167   /// Emits a diagnostic to llvm::errs().
00168   void PrintMessage(SMLoc Loc, DiagKind Kind, const Twine &Msg,
00169                     ArrayRef<SMRange> Ranges = None,
00170                     ArrayRef<SMFixIt> FixIts = None,
00171                     bool ShowColors = true) const;
00172 
00173   /// Emits a manually-constructed diagnostic to the given output stream.
00174   ///
00175   /// \param ShowColors Display colored messages if output is a terminal and
00176   /// the default error handler is used.
00177   void PrintMessage(raw_ostream &OS, const SMDiagnostic &Diagnostic,
00178                     bool ShowColors = true) const;
00179 
00180   /// Return an SMDiagnostic at the specified location with the specified
00181   /// string.
00182   ///
00183   /// \param Msg If non-null, the kind of message (e.g., "error") which is
00184   /// prefixed to the message.
00185   SMDiagnostic GetMessage(SMLoc Loc, DiagKind Kind, const Twine &Msg,
00186                           ArrayRef<SMRange> Ranges = None,
00187                           ArrayRef<SMFixIt> FixIts = None) const;
00188 
00189   /// Prints the names of included files and the line of the file they were
00190   /// included from. A diagnostic handler can use this before printing its
00191   /// custom formatted message.
00192   ///
00193   /// \param IncludeLoc The location of the include.
00194   /// \param OS the raw_ostream to print on.
00195   void PrintIncludeStack(SMLoc IncludeLoc, raw_ostream &OS) const;
00196 };
00197 
00198 
00199 /// Represents a single fixit, a replacement of one range of text with another.
00200 class SMFixIt {
00201   SMRange Range;
00202 
00203   std::string Text;
00204 
00205 public:
00206   // FIXME: Twine.str() is not very efficient.
00207   SMFixIt(SMLoc Loc, const Twine &Insertion)
00208     : Range(Loc, Loc), Text(Insertion.str()) {
00209     assert(Loc.isValid());
00210   }
00211 
00212   // FIXME: Twine.str() is not very efficient.
00213   SMFixIt(SMRange R, const Twine &Replacement)
00214     : Range(R), Text(Replacement.str()) {
00215     assert(R.isValid());
00216   }
00217 
00218   StringRef getText() const { return Text; }
00219   SMRange getRange() const { return Range; }
00220 
00221   bool operator<(const SMFixIt &Other) const {
00222     if (Range.Start.getPointer() != Other.Range.Start.getPointer())
00223       return Range.Start.getPointer() < Other.Range.Start.getPointer();
00224     if (Range.End.getPointer() != Other.Range.End.getPointer())
00225       return Range.End.getPointer() < Other.Range.End.getPointer();
00226     return Text < Other.Text;
00227   }
00228 };
00229 
00230 
00231 /// Instances of this class encapsulate one diagnostic report, allowing
00232 /// printing to a raw_ostream as a caret diagnostic.
00233 class SMDiagnostic {
00234   const SourceMgr *SM;
00235   SMLoc Loc;
00236   std::string Filename;
00237   int LineNo, ColumnNo;
00238   SourceMgr::DiagKind Kind;
00239   std::string Message, LineContents;
00240   std::vector<std::pair<unsigned, unsigned> > Ranges;
00241   SmallVector<SMFixIt, 4> FixIts;
00242 
00243 public:
00244   // Null diagnostic.
00245   SMDiagnostic()
00246     : SM(nullptr), LineNo(0), ColumnNo(0), Kind(SourceMgr::DK_Error) {}
00247   // Diagnostic with no location (e.g. file not found, command line arg error).
00248   SMDiagnostic(StringRef filename, SourceMgr::DiagKind Knd, StringRef Msg)
00249     : SM(nullptr), Filename(filename), LineNo(-1), ColumnNo(-1), Kind(Knd),
00250       Message(Msg) {}
00251 
00252   // Diagnostic with a location.
00253   SMDiagnostic(const SourceMgr &sm, SMLoc L, StringRef FN,
00254                int Line, int Col, SourceMgr::DiagKind Kind,
00255                StringRef Msg, StringRef LineStr,
00256                ArrayRef<std::pair<unsigned,unsigned> > Ranges,
00257                ArrayRef<SMFixIt> FixIts = None);
00258 
00259   const SourceMgr *getSourceMgr() const { return SM; }
00260   SMLoc getLoc() const { return Loc; }
00261   StringRef getFilename() const { return Filename; }
00262   int getLineNo() const { return LineNo; }
00263   int getColumnNo() const { return ColumnNo; }
00264   SourceMgr::DiagKind getKind() const { return Kind; }
00265   StringRef getMessage() const { return Message; }
00266   StringRef getLineContents() const { return LineContents; }
00267   ArrayRef<std::pair<unsigned, unsigned> > getRanges() const {
00268     return Ranges;
00269   }
00270 
00271   void addFixIt(const SMFixIt &Hint) {
00272     FixIts.push_back(Hint);
00273   }
00274 
00275   ArrayRef<SMFixIt> getFixIts() const {
00276     return FixIts;
00277   }
00278 
00279   void print(const char *ProgName, raw_ostream &S,
00280              bool ShowColors = true) const;
00281 };
00282 
00283 }  // end llvm namespace
00284 
00285 #endif