SourceMgr.h revision 263508
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
25namespace 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.
35class SourceMgr {
36public:
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);
47private:
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;
73public:
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  size_t 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  size_t 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  size_t 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(raw_ostream &OS, SMLoc Loc, DiagKind Kind,
148                    const Twine &Msg,
149                    ArrayRef<SMRange> Ranges = None,
150                    ArrayRef<SMFixIt> FixIts = None,
151                    bool ShowColors = true) const;
152
153  /// Emits a diagnostic to llvm::errs().
154  void PrintMessage(SMLoc Loc, DiagKind Kind, const Twine &Msg,
155                    ArrayRef<SMRange> Ranges = None,
156                    ArrayRef<SMFixIt> FixIts = None,
157                    bool ShowColors = true) const;
158
159  /// GetMessage - Return an SMDiagnostic at the specified location with the
160  /// specified string.
161  ///
162  /// @param Msg If non-null, the kind of message (e.g., "error") which is
163  /// prefixed to the message.
164  SMDiagnostic GetMessage(SMLoc Loc, DiagKind Kind, const Twine &Msg,
165                          ArrayRef<SMRange> Ranges = None,
166                          ArrayRef<SMFixIt> FixIts = None) const;
167
168  /// PrintIncludeStack - Prints the names of included files and the line of the
169  /// file they were included from.  A diagnostic handler can use this before
170  /// printing its custom formatted message.
171  ///
172  /// @param IncludeLoc - The line of the include.
173  /// @param OS the raw_ostream to print on.
174  void PrintIncludeStack(SMLoc IncludeLoc, raw_ostream &OS) const;
175};
176
177
178/// Represents a single fixit, a replacement of one range of text with another.
179class SMFixIt {
180  SMRange Range;
181
182  std::string Text;
183
184public:
185  // FIXME: Twine.str() is not very efficient.
186  SMFixIt(SMLoc Loc, const Twine &Insertion)
187    : Range(Loc, Loc), Text(Insertion.str()) {
188    assert(Loc.isValid());
189  }
190
191  // FIXME: Twine.str() is not very efficient.
192  SMFixIt(SMRange R, const Twine &Replacement)
193    : Range(R), Text(Replacement.str()) {
194    assert(R.isValid());
195  }
196
197  StringRef getText() const { return Text; }
198  SMRange getRange() const { return Range; }
199
200  bool operator<(const SMFixIt &Other) const {
201    if (Range.Start.getPointer() != Other.Range.Start.getPointer())
202      return Range.Start.getPointer() < Other.Range.Start.getPointer();
203    if (Range.End.getPointer() != Other.Range.End.getPointer())
204      return Range.End.getPointer() < Other.Range.End.getPointer();
205    return Text < Other.Text;
206  }
207};
208
209
210/// SMDiagnostic - Instances of this class encapsulate one diagnostic report,
211/// allowing printing to a raw_ostream as a caret diagnostic.
212class SMDiagnostic {
213  const SourceMgr *SM;
214  SMLoc Loc;
215  std::string Filename;
216  int LineNo, ColumnNo;
217  SourceMgr::DiagKind Kind;
218  std::string Message, LineContents;
219  std::vector<std::pair<unsigned, unsigned> > Ranges;
220  SmallVector<SMFixIt, 4> FixIts;
221
222public:
223  // Null diagnostic.
224  SMDiagnostic()
225    : SM(0), LineNo(0), ColumnNo(0), Kind(SourceMgr::DK_Error) {}
226  // Diagnostic with no location (e.g. file not found, command line arg error).
227  SMDiagnostic(StringRef filename, SourceMgr::DiagKind Knd, StringRef Msg)
228    : SM(0), Filename(filename), LineNo(-1), ColumnNo(-1), Kind(Knd),
229      Message(Msg) {}
230
231  // Diagnostic with a location.
232  SMDiagnostic(const SourceMgr &sm, SMLoc L, StringRef FN,
233               int Line, int Col, SourceMgr::DiagKind Kind,
234               StringRef Msg, StringRef LineStr,
235               ArrayRef<std::pair<unsigned,unsigned> > Ranges,
236               ArrayRef<SMFixIt> FixIts = None);
237
238  const SourceMgr *getSourceMgr() const { return SM; }
239  SMLoc getLoc() const { return Loc; }
240  StringRef getFilename() const { return Filename; }
241  int getLineNo() const { return LineNo; }
242  int getColumnNo() const { return ColumnNo; }
243  SourceMgr::DiagKind getKind() const { return Kind; }
244  StringRef getMessage() const { return Message; }
245  StringRef getLineContents() const { return LineContents; }
246  ArrayRef<std::pair<unsigned, unsigned> > getRanges() const {
247    return Ranges;
248  }
249
250  void addFixIt(const SMFixIt &Hint) {
251    FixIts.push_back(Hint);
252  }
253
254  ArrayRef<SMFixIt> getFixIts() const {
255    return FixIts;
256  }
257
258  void print(const char *ProgName, raw_ostream &S,
259             bool ShowColors = true) const;
260};
261
262}  // end llvm namespace
263
264#endif
265