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