LLVM API Documentation
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