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