Explicitly pass ownership of the MemoryBuffer to AddNewSourceBuffer using std::unique_ptr
[oota-llvm.git] / lib / Support / SourceMgr.cpp
1 //===- SourceMgr.cpp - Manager for Simple Source Buffers & Diagnostics ----===//
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 implements the SourceMgr class.  This class is used as a simple
11 // substrate for diagnostics, #include handling, and other low level things for
12 // simple parsers.
13 //
14 //===----------------------------------------------------------------------===//
15
16 #include "llvm/Support/SourceMgr.h"
17 #include "llvm/ADT/SmallString.h"
18 #include "llvm/ADT/Twine.h"
19 #include "llvm/Support/Locale.h"
20 #include "llvm/Support/MemoryBuffer.h"
21 #include "llvm/Support/Path.h"
22 #include "llvm/Support/raw_ostream.h"
23 #include <system_error>
24 using namespace llvm;
25
26 static const size_t TabStop = 8;
27
28 namespace {
29   struct LineNoCacheTy {
30     unsigned LastQueryBufferID;
31     const char *LastQuery;
32     unsigned LineNoOfQuery;
33   };
34 }
35
36 static LineNoCacheTy *getCache(void *Ptr) {
37   return (LineNoCacheTy*)Ptr;
38 }
39
40
41 SourceMgr::~SourceMgr() {
42   // Delete the line # cache if allocated.
43   if (LineNoCacheTy *Cache = getCache(LineNoCache))
44     delete Cache;
45 }
46
47 unsigned SourceMgr::AddIncludeFile(const std::string &Filename,
48                                    SMLoc IncludeLoc,
49                                    std::string &IncludedFile) {
50   IncludedFile = Filename;
51   ErrorOr<std::unique_ptr<MemoryBuffer>> NewBufOrErr =
52       MemoryBuffer::getFile(IncludedFile.c_str());
53
54   // If the file didn't exist directly, see if it's in an include path.
55   for (unsigned i = 0, e = IncludeDirectories.size(); i != e && !NewBufOrErr;
56        ++i) {
57     IncludedFile =
58         IncludeDirectories[i] + sys::path::get_separator().data() + Filename;
59     NewBufOrErr = MemoryBuffer::getFile(IncludedFile.c_str());
60   }
61
62   if (!NewBufOrErr)
63     return 0;
64
65   return AddNewSourceBuffer(std::move(*NewBufOrErr), IncludeLoc);
66 }
67
68 unsigned SourceMgr::FindBufferContainingLoc(SMLoc Loc) const {
69   for (unsigned i = 0, e = Buffers.size(); i != e; ++i)
70     if (Loc.getPointer() >= Buffers[i].Buffer->getBufferStart() &&
71         // Use <= here so that a pointer to the null at the end of the buffer
72         // is included as part of the buffer.
73         Loc.getPointer() <= Buffers[i].Buffer->getBufferEnd())
74       return i + 1;
75   return 0;
76 }
77
78 std::pair<unsigned, unsigned>
79 SourceMgr::getLineAndColumn(SMLoc Loc, unsigned BufferID) const {
80   if (!BufferID)
81     BufferID = FindBufferContainingLoc(Loc);
82   assert(BufferID && "Invalid Location!");
83
84   const MemoryBuffer *Buff = getMemoryBuffer(BufferID);
85
86   // Count the number of \n's between the start of the file and the specified
87   // location.
88   unsigned LineNo = 1;
89
90   const char *BufStart = Buff->getBufferStart();
91   const char *Ptr = BufStart;
92
93   // If we have a line number cache, and if the query is to a later point in the
94   // same file, start searching from the last query location.  This optimizes
95   // for the case when multiple diagnostics come out of one file in order.
96   if (LineNoCacheTy *Cache = getCache(LineNoCache))
97     if (Cache->LastQueryBufferID == BufferID &&
98         Cache->LastQuery <= Loc.getPointer()) {
99       Ptr = Cache->LastQuery;
100       LineNo = Cache->LineNoOfQuery;
101     }
102
103   // Scan for the location being queried, keeping track of the number of lines
104   // we see.
105   for (; SMLoc::getFromPointer(Ptr) != Loc; ++Ptr)
106     if (*Ptr == '\n') ++LineNo;
107
108   // Allocate the line number cache if it doesn't exist.
109   if (!LineNoCache)
110     LineNoCache = new LineNoCacheTy();
111
112   // Update the line # cache.
113   LineNoCacheTy &Cache = *getCache(LineNoCache);
114   Cache.LastQueryBufferID = BufferID;
115   Cache.LastQuery = Ptr;
116   Cache.LineNoOfQuery = LineNo;
117   
118   size_t NewlineOffs = StringRef(BufStart, Ptr-BufStart).find_last_of("\n\r");
119   if (NewlineOffs == StringRef::npos) NewlineOffs = ~(size_t)0;
120   return std::make_pair(LineNo, Ptr-BufStart-NewlineOffs);
121 }
122
123 void SourceMgr::PrintIncludeStack(SMLoc IncludeLoc, raw_ostream &OS) const {
124   if (IncludeLoc == SMLoc()) return;  // Top of stack.
125
126   unsigned CurBuf = FindBufferContainingLoc(IncludeLoc);
127   assert(CurBuf && "Invalid or unspecified location!");
128
129   PrintIncludeStack(getBufferInfo(CurBuf).IncludeLoc, OS);
130
131   OS << "Included from "
132      << getBufferInfo(CurBuf).Buffer->getBufferIdentifier()
133      << ":" << FindLineNumber(IncludeLoc, CurBuf) << ":\n";
134 }
135
136
137 SMDiagnostic SourceMgr::GetMessage(SMLoc Loc, SourceMgr::DiagKind Kind,
138                                    const Twine &Msg,
139                                    ArrayRef<SMRange> Ranges,
140                                    ArrayRef<SMFixIt> FixIts) const {
141
142   // First thing to do: find the current buffer containing the specified
143   // location to pull out the source line.
144   SmallVector<std::pair<unsigned, unsigned>, 4> ColRanges;
145   std::pair<unsigned, unsigned> LineAndCol;
146   const char *BufferID = "<unknown>";
147   std::string LineStr;
148   
149   if (Loc.isValid()) {
150     unsigned CurBuf = FindBufferContainingLoc(Loc);
151     assert(CurBuf && "Invalid or unspecified location!");
152
153     const MemoryBuffer *CurMB = getMemoryBuffer(CurBuf);
154     BufferID = CurMB->getBufferIdentifier();
155     
156     // Scan backward to find the start of the line.
157     const char *LineStart = Loc.getPointer();
158     const char *BufStart = CurMB->getBufferStart();
159     while (LineStart != BufStart && LineStart[-1] != '\n' &&
160            LineStart[-1] != '\r')
161       --LineStart;
162
163     // Get the end of the line.
164     const char *LineEnd = Loc.getPointer();
165     const char *BufEnd = CurMB->getBufferEnd();
166     while (LineEnd != BufEnd && LineEnd[0] != '\n' && LineEnd[0] != '\r')
167       ++LineEnd;
168     LineStr = std::string(LineStart, LineEnd);
169
170     // Convert any ranges to column ranges that only intersect the line of the
171     // location.
172     for (unsigned i = 0, e = Ranges.size(); i != e; ++i) {
173       SMRange R = Ranges[i];
174       if (!R.isValid()) continue;
175       
176       // If the line doesn't contain any part of the range, then ignore it.
177       if (R.Start.getPointer() > LineEnd || R.End.getPointer() < LineStart)
178         continue;
179      
180       // Ignore pieces of the range that go onto other lines.
181       if (R.Start.getPointer() < LineStart)
182         R.Start = SMLoc::getFromPointer(LineStart);
183       if (R.End.getPointer() > LineEnd)
184         R.End = SMLoc::getFromPointer(LineEnd);
185       
186       // Translate from SMLoc ranges to column ranges.
187       // FIXME: Handle multibyte characters.
188       ColRanges.push_back(std::make_pair(R.Start.getPointer()-LineStart,
189                                          R.End.getPointer()-LineStart));
190     }
191
192     LineAndCol = getLineAndColumn(Loc, CurBuf);
193   }
194     
195   return SMDiagnostic(*this, Loc, BufferID, LineAndCol.first,
196                       LineAndCol.second-1, Kind, Msg.str(),
197                       LineStr, ColRanges, FixIts);
198 }
199
200 void SourceMgr::PrintMessage(raw_ostream &OS, const SMDiagnostic &Diagnostic,
201                              bool ShowColors) const {
202   // Report the message with the diagnostic handler if present.
203   if (DiagHandler) {
204     DiagHandler(Diagnostic, DiagContext);
205     return;
206   }
207
208   if (Diagnostic.getLoc().isValid()) {
209     unsigned CurBuf = FindBufferContainingLoc(Diagnostic.getLoc());
210     assert(CurBuf && "Invalid or unspecified location!");
211     PrintIncludeStack(getBufferInfo(CurBuf).IncludeLoc, OS);
212   }
213
214   Diagnostic.print(nullptr, OS, ShowColors);
215 }
216
217 void SourceMgr::PrintMessage(raw_ostream &OS, SMLoc Loc,
218                              SourceMgr::DiagKind Kind,
219                              const Twine &Msg, ArrayRef<SMRange> Ranges,
220                              ArrayRef<SMFixIt> FixIts, bool ShowColors) const {
221   PrintMessage(OS, GetMessage(Loc, Kind, Msg, Ranges, FixIts), ShowColors);
222 }
223
224 void SourceMgr::PrintMessage(SMLoc Loc, SourceMgr::DiagKind Kind,
225                              const Twine &Msg, ArrayRef<SMRange> Ranges,
226                              ArrayRef<SMFixIt> FixIts, bool ShowColors) const {
227   PrintMessage(llvm::errs(), Loc, Kind, Msg, Ranges, FixIts, ShowColors);
228 }
229
230 //===----------------------------------------------------------------------===//
231 // SMDiagnostic Implementation
232 //===----------------------------------------------------------------------===//
233
234 SMDiagnostic::SMDiagnostic(const SourceMgr &sm, SMLoc L, StringRef FN,
235                            int Line, int Col, SourceMgr::DiagKind Kind,
236                            StringRef Msg, StringRef LineStr,
237                            ArrayRef<std::pair<unsigned,unsigned> > Ranges,
238                            ArrayRef<SMFixIt> Hints)
239   : SM(&sm), Loc(L), Filename(FN), LineNo(Line), ColumnNo(Col), Kind(Kind),
240     Message(Msg), LineContents(LineStr), Ranges(Ranges.vec()),
241     FixIts(Hints.begin(), Hints.end()) {
242   std::sort(FixIts.begin(), FixIts.end());
243 }
244
245 static void buildFixItLine(std::string &CaretLine, std::string &FixItLine,
246                            ArrayRef<SMFixIt> FixIts, ArrayRef<char> SourceLine){
247   if (FixIts.empty())
248     return;
249
250   const char *LineStart = SourceLine.begin();
251   const char *LineEnd = SourceLine.end();
252
253   size_t PrevHintEndCol = 0;
254
255   for (ArrayRef<SMFixIt>::iterator I = FixIts.begin(), E = FixIts.end();
256        I != E; ++I) {
257     // If the fixit contains a newline or tab, ignore it.
258     if (I->getText().find_first_of("\n\r\t") != StringRef::npos)
259       continue;
260
261     SMRange R = I->getRange();
262
263     // If the line doesn't contain any part of the range, then ignore it.
264     if (R.Start.getPointer() > LineEnd || R.End.getPointer() < LineStart)
265       continue;
266
267     // Translate from SMLoc to column.
268     // Ignore pieces of the range that go onto other lines.
269     // FIXME: Handle multibyte characters in the source line.
270     unsigned FirstCol;
271     if (R.Start.getPointer() < LineStart)
272       FirstCol = 0;
273     else
274       FirstCol = R.Start.getPointer() - LineStart;
275
276     // If we inserted a long previous hint, push this one forwards, and add
277     // an extra space to show that this is not part of the previous
278     // completion. This is sort of the best we can do when two hints appear
279     // to overlap.
280     //
281     // Note that if this hint is located immediately after the previous
282     // hint, no space will be added, since the location is more important.
283     unsigned HintCol = FirstCol;
284     if (HintCol < PrevHintEndCol)
285       HintCol = PrevHintEndCol + 1;
286
287     // FIXME: This assertion is intended to catch unintended use of multibyte
288     // characters in fixits. If we decide to do this, we'll have to track
289     // separate byte widths for the source and fixit lines.
290     assert((size_t)llvm::sys::locale::columnWidth(I->getText()) ==
291            I->getText().size());
292
293     // This relies on one byte per column in our fixit hints.
294     unsigned LastColumnModified = HintCol + I->getText().size();
295     if (LastColumnModified > FixItLine.size())
296       FixItLine.resize(LastColumnModified, ' ');
297
298     std::copy(I->getText().begin(), I->getText().end(),
299               FixItLine.begin() + HintCol);
300
301     PrevHintEndCol = LastColumnModified;
302
303     // For replacements, mark the removal range with '~'.
304     // FIXME: Handle multibyte characters in the source line.
305     unsigned LastCol;
306     if (R.End.getPointer() >= LineEnd)
307       LastCol = LineEnd - LineStart;
308     else
309       LastCol = R.End.getPointer() - LineStart;
310
311     std::fill(&CaretLine[FirstCol], &CaretLine[LastCol], '~');
312   }
313 }
314
315 static void printSourceLine(raw_ostream &S, StringRef LineContents) {
316   // Print out the source line one character at a time, so we can expand tabs.
317   for (unsigned i = 0, e = LineContents.size(), OutCol = 0; i != e; ++i) {
318     if (LineContents[i] != '\t') {
319       S << LineContents[i];
320       ++OutCol;
321       continue;
322     }
323
324     // If we have a tab, emit at least one space, then round up to 8 columns.
325     do {
326       S << ' ';
327       ++OutCol;
328     } while ((OutCol % TabStop) != 0);
329   }
330   S << '\n';
331 }
332
333 static bool isNonASCII(char c) {
334   return c & 0x80;
335 }
336
337 void SMDiagnostic::print(const char *ProgName, raw_ostream &S,
338                          bool ShowColors) const {
339   // Display colors only if OS supports colors.
340   ShowColors &= S.has_colors();
341
342   if (ShowColors)
343     S.changeColor(raw_ostream::SAVEDCOLOR, true);
344
345   if (ProgName && ProgName[0])
346     S << ProgName << ": ";
347
348   if (!Filename.empty()) {
349     if (Filename == "-")
350       S << "<stdin>";
351     else
352       S << Filename;
353
354     if (LineNo != -1) {
355       S << ':' << LineNo;
356       if (ColumnNo != -1)
357         S << ':' << (ColumnNo+1);
358     }
359     S << ": ";
360   }
361
362   switch (Kind) {
363   case SourceMgr::DK_Error:
364     if (ShowColors)
365       S.changeColor(raw_ostream::RED, true);
366     S << "error: ";
367     break;
368   case SourceMgr::DK_Warning:
369     if (ShowColors)
370       S.changeColor(raw_ostream::MAGENTA, true);
371     S << "warning: ";
372     break;
373   case SourceMgr::DK_Note:
374     if (ShowColors)
375       S.changeColor(raw_ostream::BLACK, true);
376     S << "note: ";
377     break;
378   }
379
380   if (ShowColors) {
381     S.resetColor();
382     S.changeColor(raw_ostream::SAVEDCOLOR, true);
383   }
384
385   S << Message << '\n';
386
387   if (ShowColors)
388     S.resetColor();
389
390   if (LineNo == -1 || ColumnNo == -1)
391     return;
392
393   // FIXME: If there are multibyte or multi-column characters in the source, all
394   // our ranges will be wrong. To do this properly, we'll need a byte-to-column
395   // map like Clang's TextDiagnostic. For now, we'll just handle tabs by
396   // expanding them later, and bail out rather than show incorrect ranges and
397   // misaligned fixits for any other odd characters.
398   if (std::find_if(LineContents.begin(), LineContents.end(), isNonASCII) !=
399       LineContents.end()) {
400     printSourceLine(S, LineContents);
401     return;
402   }
403   size_t NumColumns = LineContents.size();
404
405   // Build the line with the caret and ranges.
406   std::string CaretLine(NumColumns+1, ' ');
407   
408   // Expand any ranges.
409   for (unsigned r = 0, e = Ranges.size(); r != e; ++r) {
410     std::pair<unsigned, unsigned> R = Ranges[r];
411     std::fill(&CaretLine[R.first],
412               &CaretLine[std::min((size_t)R.second, CaretLine.size())],
413               '~');
414   }
415
416   // Add any fix-its.
417   // FIXME: Find the beginning of the line properly for multibyte characters.
418   std::string FixItInsertionLine;
419   buildFixItLine(CaretLine, FixItInsertionLine, FixIts,
420                  makeArrayRef(Loc.getPointer() - ColumnNo,
421                               LineContents.size()));
422
423   // Finally, plop on the caret.
424   if (unsigned(ColumnNo) <= NumColumns)
425     CaretLine[ColumnNo] = '^';
426   else 
427     CaretLine[NumColumns] = '^';
428   
429   // ... and remove trailing whitespace so the output doesn't wrap for it.  We
430   // know that the line isn't completely empty because it has the caret in it at
431   // least.
432   CaretLine.erase(CaretLine.find_last_not_of(' ')+1);
433   
434   printSourceLine(S, LineContents);
435
436   if (ShowColors)
437     S.changeColor(raw_ostream::GREEN, true);
438
439   // Print out the caret line, matching tabs in the source line.
440   for (unsigned i = 0, e = CaretLine.size(), OutCol = 0; i != e; ++i) {
441     if (i >= LineContents.size() || LineContents[i] != '\t') {
442       S << CaretLine[i];
443       ++OutCol;
444       continue;
445     }
446     
447     // Okay, we have a tab.  Insert the appropriate number of characters.
448     do {
449       S << CaretLine[i];
450       ++OutCol;
451     } while ((OutCol % TabStop) != 0);
452   }
453   S << '\n';
454
455   if (ShowColors)
456     S.resetColor();
457
458   // Print out the replacement line, matching tabs in the source line.
459   if (FixItInsertionLine.empty())
460     return;
461   
462   for (size_t i = 0, e = FixItInsertionLine.size(), OutCol = 0; i < e; ++i) {
463     if (i >= LineContents.size() || LineContents[i] != '\t') {
464       S << FixItInsertionLine[i];
465       ++OutCol;
466       continue;
467     }
468
469     // Okay, we have a tab.  Insert the appropriate number of characters.
470     do {
471       S << FixItInsertionLine[i];
472       // FIXME: This is trying not to break up replacements, but then to re-sync
473       // with the tabs between replacements. This will fail, though, if two
474       // fix-it replacements are exactly adjacent, or if a fix-it contains a
475       // space. Really we should be precomputing column widths, which we'll
476       // need anyway for multibyte chars.
477       if (FixItInsertionLine[i] != ' ')
478         ++i;
479       ++OutCol;
480     } while (((OutCol % TabStop) != 0) && i != e);
481   }
482   S << '\n';
483 }