SourceMgr.cpp revision 239462
1194612Sed//===- SourceMgr.cpp - Manager for Simple Source Buffers & Diagnostics ----===//
2194612Sed//
3194612Sed//                     The LLVM Compiler Infrastructure
4194612Sed//
5194612Sed// This file is distributed under the University of Illinois Open Source
6194612Sed// License. See LICENSE.TXT for details.
7194612Sed//
8194612Sed//===----------------------------------------------------------------------===//
9194612Sed//
10194612Sed// This file implements the SourceMgr class.  This class is used as a simple
11194612Sed// substrate for diagnostics, #include handling, and other low level things for
12194612Sed// simple parsers.
13194612Sed//
14194612Sed//===----------------------------------------------------------------------===//
15194612Sed
16218893Sdim#include "llvm/ADT/Twine.h"
17194612Sed#include "llvm/Support/SourceMgr.h"
18194612Sed#include "llvm/Support/MemoryBuffer.h"
19218893Sdim#include "llvm/ADT/OwningPtr.h"
20194612Sed#include "llvm/Support/raw_ostream.h"
21218893Sdim#include "llvm/Support/system_error.h"
22194612Sedusing namespace llvm;
23194612Sed
24198090Srdivackynamespace {
25198090Srdivacky  struct LineNoCacheTy {
26198090Srdivacky    int LastQueryBufferID;
27198090Srdivacky    const char *LastQuery;
28198090Srdivacky    unsigned LineNoOfQuery;
29198090Srdivacky  };
30198090Srdivacky}
31198090Srdivacky
32198090Srdivackystatic LineNoCacheTy *getCache(void *Ptr) {
33198090Srdivacky  return (LineNoCacheTy*)Ptr;
34198090Srdivacky}
35198090Srdivacky
36198090Srdivacky
37194612SedSourceMgr::~SourceMgr() {
38198090Srdivacky  // Delete the line # cache if allocated.
39198090Srdivacky  if (LineNoCacheTy *Cache = getCache(LineNoCache))
40198090Srdivacky    delete Cache;
41203954Srdivacky
42194612Sed  while (!Buffers.empty()) {
43194612Sed    delete Buffers.back().Buffer;
44194612Sed    Buffers.pop_back();
45194612Sed  }
46194612Sed}
47194612Sed
48194612Sed/// AddIncludeFile - Search for a file with the specified name in the current
49194612Sed/// directory or in one of the IncludeDirs.  If no file is found, this returns
50194612Sed/// ~0, otherwise it returns the buffer ID of the stacked file.
51194612Sedunsigned SourceMgr::AddIncludeFile(const std::string &Filename,
52223017Sdim                                   SMLoc IncludeLoc,
53223017Sdim                                   std::string &IncludedFile) {
54218893Sdim  OwningPtr<MemoryBuffer> NewBuf;
55223017Sdim  IncludedFile = Filename;
56223017Sdim  MemoryBuffer::getFile(IncludedFile.c_str(), NewBuf);
57203954Srdivacky
58194612Sed  // If the file didn't exist directly, see if it's in an include path.
59194612Sed  for (unsigned i = 0, e = IncludeDirectories.size(); i != e && !NewBuf; ++i) {
60223017Sdim    IncludedFile = IncludeDirectories[i] + "/" + Filename;
61223017Sdim    MemoryBuffer::getFile(IncludedFile.c_str(), NewBuf);
62194612Sed  }
63203954Srdivacky
64194612Sed  if (NewBuf == 0) return ~0U;
65194612Sed
66218893Sdim  return AddNewSourceBuffer(NewBuf.take(), IncludeLoc);
67194612Sed}
68194612Sed
69194612Sed
70194612Sed/// FindBufferContainingLoc - Return the ID of the buffer containing the
71194612Sed/// specified location, returning -1 if not found.
72194612Sedint SourceMgr::FindBufferContainingLoc(SMLoc Loc) const {
73194612Sed  for (unsigned i = 0, e = Buffers.size(); i != e; ++i)
74194612Sed    if (Loc.getPointer() >= Buffers[i].Buffer->getBufferStart() &&
75194612Sed        // Use <= here so that a pointer to the null at the end of the buffer
76194612Sed        // is included as part of the buffer.
77194612Sed        Loc.getPointer() <= Buffers[i].Buffer->getBufferEnd())
78194612Sed      return i;
79194612Sed  return -1;
80194612Sed}
81194612Sed
82239462Sdim/// getLineAndColumn - Find the line and column number for the specified
83239462Sdim/// location in the specified file.  This is not a fast method.
84239462Sdimstd::pair<unsigned, unsigned>
85239462SdimSourceMgr::getLineAndColumn(SMLoc Loc, int BufferID) const {
86194612Sed  if (BufferID == -1) BufferID = FindBufferContainingLoc(Loc);
87194612Sed  assert(BufferID != -1 && "Invalid Location!");
88203954Srdivacky
89194612Sed  MemoryBuffer *Buff = getBufferInfo(BufferID).Buffer;
90203954Srdivacky
91194612Sed  // Count the number of \n's between the start of the file and the specified
92194612Sed  // location.
93194612Sed  unsigned LineNo = 1;
94203954Srdivacky
95239462Sdim  const char *BufStart = Buff->getBufferStart();
96239462Sdim  const char *Ptr = BufStart;
97194612Sed
98198090Srdivacky  // If we have a line number cache, and if the query is to a later point in the
99198090Srdivacky  // same file, start searching from the last query location.  This optimizes
100198090Srdivacky  // for the case when multiple diagnostics come out of one file in order.
101198090Srdivacky  if (LineNoCacheTy *Cache = getCache(LineNoCache))
102203954Srdivacky    if (Cache->LastQueryBufferID == BufferID &&
103198090Srdivacky        Cache->LastQuery <= Loc.getPointer()) {
104198090Srdivacky      Ptr = Cache->LastQuery;
105198090Srdivacky      LineNo = Cache->LineNoOfQuery;
106198090Srdivacky    }
107198090Srdivacky
108198090Srdivacky  // Scan for the location being queried, keeping track of the number of lines
109198090Srdivacky  // we see.
110194612Sed  for (; SMLoc::getFromPointer(Ptr) != Loc; ++Ptr)
111194612Sed    if (*Ptr == '\n') ++LineNo;
112203954Srdivacky
113198090Srdivacky  // Allocate the line number cache if it doesn't exist.
114198090Srdivacky  if (LineNoCache == 0)
115198090Srdivacky    LineNoCache = new LineNoCacheTy();
116203954Srdivacky
117198090Srdivacky  // Update the line # cache.
118198090Srdivacky  LineNoCacheTy &Cache = *getCache(LineNoCache);
119198090Srdivacky  Cache.LastQueryBufferID = BufferID;
120198090Srdivacky  Cache.LastQuery = Ptr;
121198090Srdivacky  Cache.LineNoOfQuery = LineNo;
122239462Sdim
123239462Sdim  size_t NewlineOffs = StringRef(BufStart, Ptr-BufStart).find_last_of("\n\r");
124239462Sdim  if (NewlineOffs == StringRef::npos) NewlineOffs = ~(size_t)0;
125239462Sdim  return std::make_pair(LineNo, Ptr-BufStart-NewlineOffs);
126194612Sed}
127194612Sed
128195340Sedvoid SourceMgr::PrintIncludeStack(SMLoc IncludeLoc, raw_ostream &OS) const {
129194612Sed  if (IncludeLoc == SMLoc()) return;  // Top of stack.
130203954Srdivacky
131194612Sed  int CurBuf = FindBufferContainingLoc(IncludeLoc);
132194612Sed  assert(CurBuf != -1 && "Invalid or unspecified location!");
133194612Sed
134195340Sed  PrintIncludeStack(getBufferInfo(CurBuf).IncludeLoc, OS);
135203954Srdivacky
136195340Sed  OS << "Included from "
137195340Sed     << getBufferInfo(CurBuf).Buffer->getBufferIdentifier()
138195340Sed     << ":" << FindLineNumber(IncludeLoc, CurBuf) << ":\n";
139194612Sed}
140194612Sed
141194612Sed
142195340Sed/// GetMessage - Return an SMDiagnostic at the specified location with the
143195340Sed/// specified string.
144195340Sed///
145195340Sed/// @param Type - If non-null, the kind of message (e.g., "error") which is
146195340Sed/// prefixed to the message.
147234353SdimSMDiagnostic SourceMgr::GetMessage(SMLoc Loc, SourceMgr::DiagKind Kind,
148234353Sdim                                   const Twine &Msg,
149234353Sdim                                   ArrayRef<SMRange> Ranges) const {
150203954Srdivacky
151194612Sed  // First thing to do: find the current buffer containing the specified
152239462Sdim  // location to pull out the source line.
153239462Sdim  SmallVector<std::pair<unsigned, unsigned>, 4> ColRanges;
154239462Sdim  std::pair<unsigned, unsigned> LineAndCol;
155239462Sdim  const char *BufferID = "<unknown>";
156239462Sdim  std::string LineStr;
157239462Sdim
158239462Sdim  if (Loc.isValid()) {
159239462Sdim    int CurBuf = FindBufferContainingLoc(Loc);
160239462Sdim    assert(CurBuf != -1 && "Invalid or unspecified location!");
161203954Srdivacky
162239462Sdim    MemoryBuffer *CurMB = getBufferInfo(CurBuf).Buffer;
163239462Sdim    BufferID = CurMB->getBufferIdentifier();
164239462Sdim
165239462Sdim    // Scan backward to find the start of the line.
166239462Sdim    const char *LineStart = Loc.getPointer();
167239462Sdim    const char *BufStart = CurMB->getBufferStart();
168239462Sdim    while (LineStart != BufStart && LineStart[-1] != '\n' &&
169239462Sdim           LineStart[-1] != '\r')
170239462Sdim      --LineStart;
171199989Srdivacky
172239462Sdim    // Get the end of the line.
173239462Sdim    const char *LineEnd = Loc.getPointer();
174239462Sdim    const char *BufEnd = CurMB->getBufferEnd();
175239462Sdim    while (LineEnd != BufEnd && LineEnd[0] != '\n' && LineEnd[0] != '\r')
176239462Sdim      ++LineEnd;
177239462Sdim    LineStr = std::string(LineStart, LineEnd);
178199989Srdivacky
179239462Sdim    // Convert any ranges to column ranges that only intersect the line of the
180239462Sdim    // location.
181239462Sdim    for (unsigned i = 0, e = Ranges.size(); i != e; ++i) {
182239462Sdim      SMRange R = Ranges[i];
183239462Sdim      if (!R.isValid()) continue;
184239462Sdim
185239462Sdim      // If the line doesn't contain any part of the range, then ignore it.
186239462Sdim      if (R.Start.getPointer() > LineEnd || R.End.getPointer() < LineStart)
187239462Sdim        continue;
188239462Sdim
189239462Sdim      // Ignore pieces of the range that go onto other lines.
190239462Sdim      if (R.Start.getPointer() < LineStart)
191239462Sdim        R.Start = SMLoc::getFromPointer(LineStart);
192239462Sdim      if (R.End.getPointer() > LineEnd)
193239462Sdim        R.End = SMLoc::getFromPointer(LineEnd);
194239462Sdim
195239462Sdim      // Translate from SMLoc ranges to column ranges.
196239462Sdim      ColRanges.push_back(std::make_pair(R.Start.getPointer()-LineStart,
197239462Sdim                                         R.End.getPointer()-LineStart));
198239462Sdim    }
199234353Sdim
200239462Sdim    LineAndCol = getLineAndColumn(Loc, CurBuf);
201239462Sdim  }
202234353Sdim
203239462Sdim  return SMDiagnostic(*this, Loc, BufferID, LineAndCol.first,
204239462Sdim                      LineAndCol.second-1, Kind, Msg.str(),
205234353Sdim                      LineStr, ColRanges);
206194612Sed}
207195340Sed
208234353Sdimvoid SourceMgr::PrintMessage(SMLoc Loc, SourceMgr::DiagKind Kind,
209234982Sdim                             const Twine &Msg, ArrayRef<SMRange> Ranges,
210234982Sdim                             bool ShowColors) const {
211234353Sdim  SMDiagnostic Diagnostic = GetMessage(Loc, Kind, Msg, Ranges);
212234353Sdim
213206274Srdivacky  // Report the message with the diagnostic handler if present.
214206274Srdivacky  if (DiagHandler) {
215234353Sdim    DiagHandler(Diagnostic, DiagContext);
216206274Srdivacky    return;
217206274Srdivacky  }
218218893Sdim
219195340Sed  raw_ostream &OS = errs();
220195340Sed
221239462Sdim  if (Loc != SMLoc()) {
222239462Sdim    int CurBuf = FindBufferContainingLoc(Loc);
223239462Sdim    assert(CurBuf != -1 && "Invalid or unspecified location!");
224239462Sdim    PrintIncludeStack(getBufferInfo(CurBuf).IncludeLoc, OS);
225239462Sdim  }
226195340Sed
227234982Sdim  Diagnostic.print(0, OS, ShowColors);
228195340Sed}
229195340Sed
230195340Sed//===----------------------------------------------------------------------===//
231195340Sed// SMDiagnostic Implementation
232195340Sed//===----------------------------------------------------------------------===//
233195340Sed
234234353SdimSMDiagnostic::SMDiagnostic(const SourceMgr &sm, SMLoc L, const std::string &FN,
235234353Sdim                           int Line, int Col, SourceMgr::DiagKind Kind,
236234353Sdim                           const std::string &Msg,
237234353Sdim                           const std::string &LineStr,
238234353Sdim                           ArrayRef<std::pair<unsigned,unsigned> > Ranges)
239234353Sdim  : SM(&sm), Loc(L), Filename(FN), LineNo(Line), ColumnNo(Col), Kind(Kind),
240234353Sdim    Message(Msg), LineContents(LineStr), Ranges(Ranges.vec()) {
241234353Sdim}
242234353Sdim
243234353Sdim
244234982Sdimvoid SMDiagnostic::print(const char *ProgName, raw_ostream &S,
245234982Sdim                         bool ShowColors) const {
246239462Sdim  // Display colors only if OS supports colors.
247239462Sdim  ShowColors &= S.has_colors();
248234982Sdim
249234982Sdim  if (ShowColors)
250234982Sdim    S.changeColor(raw_ostream::SAVEDCOLOR, true);
251234982Sdim
252195340Sed  if (ProgName && ProgName[0])
253195340Sed    S << ProgName << ": ";
254195340Sed
255202878Srdivacky  if (!Filename.empty()) {
256202878Srdivacky    if (Filename == "-")
257202878Srdivacky      S << "<stdin>";
258202878Srdivacky    else
259202878Srdivacky      S << Filename;
260203954Srdivacky
261202878Srdivacky    if (LineNo != -1) {
262202878Srdivacky      S << ':' << LineNo;
263202878Srdivacky      if (ColumnNo != -1)
264202878Srdivacky        S << ':' << (ColumnNo+1);
265202878Srdivacky    }
266202878Srdivacky    S << ": ";
267195340Sed  }
268203954Srdivacky
269234353Sdim  switch (Kind) {
270234982Sdim  case SourceMgr::DK_Error:
271234982Sdim    if (ShowColors)
272234982Sdim      S.changeColor(raw_ostream::RED, true);
273234982Sdim    S << "error: ";
274234982Sdim    break;
275234982Sdim  case SourceMgr::DK_Warning:
276234982Sdim    if (ShowColors)
277234982Sdim      S.changeColor(raw_ostream::MAGENTA, true);
278234982Sdim    S << "warning: ";
279234982Sdim    break;
280234982Sdim  case SourceMgr::DK_Note:
281234982Sdim    if (ShowColors)
282234982Sdim      S.changeColor(raw_ostream::BLACK, true);
283234982Sdim    S << "note: ";
284234982Sdim    break;
285234353Sdim  }
286234982Sdim
287234982Sdim  if (ShowColors) {
288234982Sdim    S.resetColor();
289234982Sdim    S.changeColor(raw_ostream::SAVEDCOLOR, true);
290234982Sdim  }
291234982Sdim
292202878Srdivacky  S << Message << '\n';
293199989Srdivacky
294234982Sdim  if (ShowColors)
295234982Sdim    S.resetColor();
296234982Sdim
297234353Sdim  if (LineNo == -1 || ColumnNo == -1)
298234353Sdim    return;
299203954Srdivacky
300234353Sdim  // Build the line with the caret and ranges.
301234353Sdim  std::string CaretLine(LineContents.size()+1, ' ');
302234353Sdim
303234353Sdim  // Expand any ranges.
304234353Sdim  for (unsigned r = 0, e = Ranges.size(); r != e; ++r) {
305234353Sdim    std::pair<unsigned, unsigned> R = Ranges[r];
306234353Sdim    for (unsigned i = R.first,
307234353Sdim         e = std::min(R.second, (unsigned)LineContents.size())+1; i != e; ++i)
308234353Sdim      CaretLine[i] = '~';
309195340Sed  }
310234353Sdim
311234353Sdim  // Finally, plop on the caret.
312234353Sdim  if (unsigned(ColumnNo) <= LineContents.size())
313234353Sdim    CaretLine[ColumnNo] = '^';
314234353Sdim  else
315234353Sdim    CaretLine[LineContents.size()] = '^';
316234353Sdim
317234353Sdim  // ... and remove trailing whitespace so the output doesn't wrap for it.  We
318234353Sdim  // know that the line isn't completely empty because it has the caret in it at
319234353Sdim  // least.
320234353Sdim  CaretLine.erase(CaretLine.find_last_not_of(' ')+1);
321234353Sdim
322234353Sdim  // Print out the source line one character at a time, so we can expand tabs.
323234353Sdim  for (unsigned i = 0, e = LineContents.size(), OutCol = 0; i != e; ++i) {
324234353Sdim    if (LineContents[i] != '\t') {
325234353Sdim      S << LineContents[i];
326234353Sdim      ++OutCol;
327234353Sdim      continue;
328234353Sdim    }
329234353Sdim
330234353Sdim    // If we have a tab, emit at least one space, then round up to 8 columns.
331234353Sdim    do {
332234353Sdim      S << ' ';
333234353Sdim      ++OutCol;
334234353Sdim    } while (OutCol & 7);
335234353Sdim  }
336234353Sdim  S << '\n';
337234353Sdim
338234982Sdim  if (ShowColors)
339234982Sdim    S.changeColor(raw_ostream::GREEN, true);
340234982Sdim
341234353Sdim  // Print out the caret line, matching tabs in the source line.
342234353Sdim  for (unsigned i = 0, e = CaretLine.size(), OutCol = 0; i != e; ++i) {
343234353Sdim    if (i >= LineContents.size() || LineContents[i] != '\t') {
344234353Sdim      S << CaretLine[i];
345234353Sdim      ++OutCol;
346234353Sdim      continue;
347234353Sdim    }
348234353Sdim
349234353Sdim    // Okay, we have a tab.  Insert the appropriate number of characters.
350234353Sdim    do {
351234353Sdim      S << CaretLine[i];
352234353Sdim      ++OutCol;
353234353Sdim    } while (OutCol & 7);
354234353Sdim  }
355234982Sdim
356234982Sdim  if (ShowColors)
357234982Sdim    S.resetColor();
358234353Sdim
359234353Sdim  S << '\n';
360195340Sed}
361