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