SourceMgr.h revision 327952
11558Srgrimes//===- SourceMgr.h - Manager for Source Buffers & Diagnostics ---*- C++ -*-===// 21558Srgrimes// 31558Srgrimes// The LLVM Compiler Infrastructure 41558Srgrimes// 51558Srgrimes// This file is distributed under the University of Illinois Open Source 61558Srgrimes// License. See LICENSE.TXT for details. 71558Srgrimes// 81558Srgrimes//===----------------------------------------------------------------------===// 91558Srgrimes// 101558Srgrimes// This file declares the SMDiagnostic and SourceMgr classes. This 111558Srgrimes// provides a simple substrate for diagnostics, #include handling, and other low 121558Srgrimes// level things for simple parsers. 131558Srgrimes// 141558Srgrimes//===----------------------------------------------------------------------===// 151558Srgrimes 161558Srgrimes#ifndef LLVM_SUPPORT_SOURCEMGR_H 171558Srgrimes#define LLVM_SUPPORT_SOURCEMGR_H 181558Srgrimes 191558Srgrimes#include "llvm/ADT/ArrayRef.h" 201558Srgrimes#include "llvm/ADT/None.h" 211558Srgrimes#include "llvm/ADT/SmallVector.h" 221558Srgrimes#include "llvm/ADT/StringRef.h" 231558Srgrimes#include "llvm/ADT/Twine.h" 241558Srgrimes#include "llvm/Support/MemoryBuffer.h" 251558Srgrimes#include "llvm/Support/SMLoc.h" 261558Srgrimes#include <algorithm> 271558Srgrimes#include <cassert> 281558Srgrimes#include <memory> 291558Srgrimes#include <string> 301558Srgrimes#include <utility> 311558Srgrimes#include <vector> 321558Srgrimes 331558Srgrimesnamespace llvm { 341558Srgrimes 351558Srgrimesclass raw_ostream; 361558Srgrimesclass SMDiagnostic; 371558Srgrimesclass SMFixIt; 3836630Scharnier 391558Srgrimes/// This owns the files read by a parser, handles include stacks, 401558Srgrimes/// and handles diagnostic wrangling. 411558Srgrimesclass SourceMgr { 421558Srgrimespublic: 431558Srgrimes enum DiagKind { 4436630Scharnier DK_Error, 451558Srgrimes DK_Warning, 4636630Scharnier DK_Remark, 471558Srgrimes DK_Note, 481558Srgrimes }; 4999364Smarkm 5099364Smarkm /// Clients that want to handle their own diagnostics in a custom way can 5199364Smarkm /// register a function pointer+context as a diagnostic handler. 521558Srgrimes /// It gets called each time PrintMessage is invoked. 5396478Sphk using DiagHandlerTy = void (*)(const SMDiagnostic &, void *Context); 541558Srgrimes 551558Srgrimesprivate: 561558Srgrimes struct SrcBuffer { 571558Srgrimes /// The memory buffer for the file. 581558Srgrimes std::unique_ptr<MemoryBuffer> Buffer; 591558Srgrimes 601558Srgrimes /// This is the location of the parent include, or null if at the top level. 611558Srgrimes SMLoc IncludeLoc; 621558Srgrimes }; 631558Srgrimes 641558Srgrimes /// This is all of the buffers that we are reading from. 6598542Smckusick std::vector<SrcBuffer> Buffers; 6698542Smckusick 6798542Smckusick // This is the list of directories we should search for include files in. 6898542Smckusick std::vector<std::string> IncludeDirectories; 6998542Smckusick 7036630Scharnier /// This is a cache for line number queries, its implementation is really 7136630Scharnier /// private to SourceMgr.cpp. 7236630Scharnier mutable void *LineNoCache = nullptr; 7336630Scharnier 7436630Scharnier DiagHandlerTy DiagHandler = nullptr; 7536630Scharnier void *DiagContext = nullptr; 7636630Scharnier 771558Srgrimes bool isValidBufferID(unsigned i) const { return i && i <= Buffers.size(); } 7899364Smarkm 791558Srgrimespublic: 8092753Simp SourceMgr() = default; 8198542Smckusick SourceMgr(const SourceMgr &) = delete; 8298542Smckusick SourceMgr &operator=(const SourceMgr &) = delete; 8398542Smckusick ~SourceMgr(); 841558Srgrimes 851558Srgrimes void setIncludeDirs(const std::vector<std::string> &Dirs) { 8698542Smckusick IncludeDirectories = Dirs; 8798542Smckusick } 881558Srgrimes 8936630Scharnier /// Specify a diagnostic handler to be invoked every time PrintMessage is 9036630Scharnier /// called. \p Ctx is passed into the handler when it is invoked. 911558Srgrimes void setDiagHandler(DiagHandlerTy DH, void *Ctx = nullptr) { 921558Srgrimes DiagHandler = DH; 931558Srgrimes DiagContext = Ctx; 941558Srgrimes } 951558Srgrimes 961558Srgrimes DiagHandlerTy getDiagHandler() const { return DiagHandler; } 9798542Smckusick void *getDiagContext() const { return DiagContext; } 9898542Smckusick 9998542Smckusick const SrcBuffer &getBufferInfo(unsigned i) const { 10098542Smckusick assert(isValidBufferID(i)); 10198542Smckusick return Buffers[i - 1]; 10298542Smckusick } 10398542Smckusick 10498542Smckusick const MemoryBuffer *getMemoryBuffer(unsigned i) const { 10598542Smckusick assert(isValidBufferID(i)); 10698542Smckusick return Buffers[i - 1].Buffer.get(); 10799364Smarkm } 10898542Smckusick 10998542Smckusick unsigned getNumBuffers() const { 11098542Smckusick return Buffers.size(); 11198542Smckusick } 11298542Smckusick 11398542Smckusick unsigned getMainFileID() const { 1141558Srgrimes assert(getNumBuffers()); 1151558Srgrimes return 1; 1161558Srgrimes } 1171558Srgrimes 1181558Srgrimes SMLoc getParentIncludeLoc(unsigned i) const { 11926438Scharnier assert(isValidBufferID(i)); 12036630Scharnier return Buffers[i - 1].IncludeLoc; 1211558Srgrimes } 1221558Srgrimes 1231558Srgrimes /// Add a new source buffer to this source manager. This takes ownership of 1241558Srgrimes /// the memory buffer. 1251558Srgrimes unsigned AddNewSourceBuffer(std::unique_ptr<MemoryBuffer> F, 1261558Srgrimes SMLoc IncludeLoc) { 1271558Srgrimes SrcBuffer NB; 1281558Srgrimes NB.Buffer = std::move(F); 1291558Srgrimes NB.IncludeLoc = IncludeLoc; 1301558Srgrimes Buffers.push_back(std::move(NB)); 1311558Srgrimes return Buffers.size(); 1321558Srgrimes } 1331558Srgrimes 13498542Smckusick /// Search for a file with the specified name in the current directory or in 13598542Smckusick /// one of the IncludeDirs. 13698542Smckusick /// 13798542Smckusick /// If no file is found, this returns 0, otherwise it returns the buffer ID 1381558Srgrimes /// of the stacked file. The full path to the included file can be found in 13998542Smckusick /// \p IncludedFile. 14098542Smckusick unsigned AddIncludeFile(const std::string &Filename, SMLoc IncludeLoc, 14198542Smckusick std::string &IncludedFile); 14298542Smckusick 14398542Smckusick /// Return the ID of the buffer containing the specified location. 14498542Smckusick /// 14598542Smckusick /// 0 is returned if the buffer is not found. 14698542Smckusick unsigned FindBufferContainingLoc(SMLoc Loc) const; 1471558Srgrimes 14898542Smckusick /// Find the line number for the specified location in the specified file. 14998542Smckusick /// This is not a fast method. 15098542Smckusick unsigned FindLineNumber(SMLoc Loc, unsigned BufferID = 0) const { 15198542Smckusick return getLineAndColumn(Loc, BufferID).first; 15298542Smckusick } 15398542Smckusick 1541558Srgrimes /// Find the line and column number for the specified location in the 1551558Srgrimes /// specified file. This is not a fast method. 1561558Srgrimes std::pair<unsigned, unsigned> getLineAndColumn(SMLoc Loc, 1571558Srgrimes unsigned BufferID = 0) const; 1581558Srgrimes 1591558Srgrimes /// Emit a message about the specified location with the specified string. 1601558Srgrimes /// 1611558Srgrimes /// \param ShowColors Display colored messages if output is a terminal and 1621558Srgrimes /// the default error handler is used. 1631558Srgrimes void PrintMessage(raw_ostream &OS, SMLoc Loc, DiagKind Kind, 164 const Twine &Msg, 165 ArrayRef<SMRange> Ranges = None, 166 ArrayRef<SMFixIt> FixIts = None, 167 bool ShowColors = true) const; 168 169 /// Emits a diagnostic to llvm::errs(). 170 void PrintMessage(SMLoc Loc, DiagKind Kind, const Twine &Msg, 171 ArrayRef<SMRange> Ranges = None, 172 ArrayRef<SMFixIt> FixIts = None, 173 bool ShowColors = true) const; 174 175 /// Emits a manually-constructed diagnostic to the given output stream. 176 /// 177 /// \param ShowColors Display colored messages if output is a terminal and 178 /// the default error handler is used. 179 void PrintMessage(raw_ostream &OS, const SMDiagnostic &Diagnostic, 180 bool ShowColors = true) const; 181 182 /// Return an SMDiagnostic at the specified location with the specified 183 /// string. 184 /// 185 /// \param Msg If non-null, the kind of message (e.g., "error") which is 186 /// prefixed to the message. 187 SMDiagnostic GetMessage(SMLoc Loc, DiagKind Kind, const Twine &Msg, 188 ArrayRef<SMRange> Ranges = None, 189 ArrayRef<SMFixIt> FixIts = None) const; 190 191 /// Prints the names of included files and the line of the file they were 192 /// included from. A diagnostic handler can use this before printing its 193 /// custom formatted message. 194 /// 195 /// \param IncludeLoc The location of the include. 196 /// \param OS the raw_ostream to print on. 197 void PrintIncludeStack(SMLoc IncludeLoc, raw_ostream &OS) const; 198}; 199 200/// Represents a single fixit, a replacement of one range of text with another. 201class SMFixIt { 202 SMRange Range; 203 204 std::string Text; 205 206public: 207 // FIXME: Twine.str() is not very efficient. 208 SMFixIt(SMLoc Loc, const Twine &Insertion) 209 : Range(Loc, Loc), Text(Insertion.str()) { 210 assert(Loc.isValid()); 211 } 212 213 // FIXME: Twine.str() is not very efficient. 214 SMFixIt(SMRange R, const Twine &Replacement) 215 : Range(R), Text(Replacement.str()) { 216 assert(R.isValid()); 217 } 218 219 StringRef getText() const { return Text; } 220 SMRange getRange() const { return Range; } 221 222 bool operator<(const SMFixIt &Other) const { 223 if (Range.Start.getPointer() != Other.Range.Start.getPointer()) 224 return Range.Start.getPointer() < Other.Range.Start.getPointer(); 225 if (Range.End.getPointer() != Other.Range.End.getPointer()) 226 return Range.End.getPointer() < Other.Range.End.getPointer(); 227 return Text < Other.Text; 228 } 229}; 230 231/// Instances of this class encapsulate one diagnostic report, allowing 232/// printing to a raw_ostream as a caret diagnostic. 233class SMDiagnostic { 234 const SourceMgr *SM = nullptr; 235 SMLoc Loc; 236 std::string Filename; 237 int LineNo = 0; 238 int ColumnNo = 0; 239 SourceMgr::DiagKind Kind = SourceMgr::DK_Error; 240 std::string Message, LineContents; 241 std::vector<std::pair<unsigned, unsigned>> Ranges; 242 SmallVector<SMFixIt, 4> FixIts; 243 244public: 245 // Null diagnostic. 246 SMDiagnostic() = default; 247 // Diagnostic with no location (e.g. file not found, command line arg error). 248 SMDiagnostic(StringRef filename, SourceMgr::DiagKind Knd, StringRef Msg) 249 : Filename(filename), LineNo(-1), ColumnNo(-1), Kind(Knd), Message(Msg) {} 250 251 // Diagnostic with a location. 252 SMDiagnostic(const SourceMgr &sm, SMLoc L, StringRef FN, 253 int Line, int Col, SourceMgr::DiagKind Kind, 254 StringRef Msg, StringRef LineStr, 255 ArrayRef<std::pair<unsigned,unsigned>> Ranges, 256 ArrayRef<SMFixIt> FixIts = None); 257 258 const SourceMgr *getSourceMgr() const { return SM; } 259 SMLoc getLoc() const { return Loc; } 260 StringRef getFilename() const { return Filename; } 261 int getLineNo() const { return LineNo; } 262 int getColumnNo() const { return ColumnNo; } 263 SourceMgr::DiagKind getKind() const { return Kind; } 264 StringRef getMessage() const { return Message; } 265 StringRef getLineContents() const { return LineContents; } 266 ArrayRef<std::pair<unsigned, unsigned>> getRanges() const { return Ranges; } 267 268 void addFixIt(const SMFixIt &Hint) { 269 FixIts.push_back(Hint); 270 } 271 272 ArrayRef<SMFixIt> getFixIts() const { 273 return FixIts; 274 } 275 276 void print(const char *ProgName, raw_ostream &S, bool ShowColors = true, 277 bool ShowKindLabel = true) const; 278}; 279 280} // end namespace llvm 281 282#endif // LLVM_SUPPORT_SOURCEMGR_H 283