Coverage Report

Created: 2019-07-24 05:18

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/lib/Support/SourceMgr.cpp
Line
Count
Source (jump to first uncovered line)
1
//===- SourceMgr.cpp - Manager for Simple Source Buffers & Diagnostics ----===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
// This file implements the SourceMgr class.  This class is used as a simple
10
// substrate for diagnostics, #include handling, and other low level things for
11
// simple parsers.
12
//
13
//===----------------------------------------------------------------------===//
14
15
#include "llvm/Support/SourceMgr.h"
16
#include "llvm/ADT/ArrayRef.h"
17
#include "llvm/ADT/STLExtras.h"
18
#include "llvm/ADT/SmallVector.h"
19
#include "llvm/ADT/StringRef.h"
20
#include "llvm/ADT/Twine.h"
21
#include "llvm/Support/ErrorOr.h"
22
#include "llvm/Support/Locale.h"
23
#include "llvm/Support/MemoryBuffer.h"
24
#include "llvm/Support/Path.h"
25
#include "llvm/Support/SMLoc.h"
26
#include "llvm/Support/WithColor.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
unsigned SourceMgr::AddIncludeFile(const std::string &Filename,
41
                                   SMLoc IncludeLoc,
42
9.42k
                                   std::string &IncludedFile) {
43
9.42k
  IncludedFile = Filename;
44
9.42k
  ErrorOr<std::unique_ptr<MemoryBuffer>> NewBufOrErr =
45
9.42k
    MemoryBuffer::getFile(IncludedFile);
46
9.42k
47
9.42k
  // If the file didn't exist directly, see if it's in an include path.
48
23.9k
  for (unsigned i = 0, e = IncludeDirectories.size(); i != e && 
!NewBufOrErr22.8k
;
49
14.4k
       ++i) {
50
14.4k
    IncludedFile =
51
14.4k
        IncludeDirectories[i] + sys::path::get_separator().data() + Filename;
52
14.4k
    NewBufOrErr = MemoryBuffer::getFile(IncludedFile);
53
14.4k
  }
54
9.42k
55
9.42k
  if (!NewBufOrErr)
56
0
    return 0;
57
9.42k
58
9.42k
  return AddNewSourceBuffer(std::move(*NewBufOrErr), IncludeLoc);
59
9.42k
}
60
61
370k
unsigned SourceMgr::FindBufferContainingLoc(SMLoc Loc) const {
62
538k
  for (unsigned i = 0, e = Buffers.size(); i != e; 
++i167k
)
63
450k
    if (Loc.getPointer() >= Buffers[i].Buffer->getBufferStart() &&
64
450k
        // Use <= here so that a pointer to the null at the end of the buffer
65
450k
        // is included as part of the buffer.
66
450k
        
Loc.getPointer() <= Buffers[i].Buffer->getBufferEnd()330k
)
67
282k
      return i + 1;
68
370k
  
return 087.6k
;
69
370k
}
70
71
template <typename T>
72
95.7k
unsigned SourceMgr::SrcBuffer::getLineNumber(const char *Ptr) const {
73
95.7k
74
95.7k
  // Ensure OffsetCache is allocated and populated with offsets of all the
75
95.7k
  // '\n' bytes.
76
95.7k
  std::vector<T> *Offsets = nullptr;
77
95.7k
  if (OffsetCache.isNull()) {
78
3.88k
    Offsets = new std::vector<T>();
79
3.88k
    OffsetCache = Offsets;
80
3.88k
    size_t Sz = Buffer->getBufferSize();
81
3.88k
    assert(Sz <= std::numeric_limits<T>::max());
82
3.88k
    StringRef S = Buffer->getBuffer();
83
36.5M
    for (size_t N = 0; N < Sz; 
++N36.5M
) {
84
36.5M
      if (S[N] == '\n') {
85
954k
        Offsets->push_back(static_cast<T>(N));
86
954k
      }
87
36.5M
    }
88
91.8k
  } else {
89
91.8k
    Offsets = OffsetCache.get<std::vector<T> *>();
90
91.8k
  }
91
95.7k
92
95.7k
  const char *BufStart = Buffer->getBufferStart();
93
95.7k
  assert(Ptr >= BufStart && Ptr <= Buffer->getBufferEnd());
94
95.7k
  ptrdiff_t PtrDiff = Ptr - BufStart;
95
95.7k
  assert(PtrDiff >= 0 && static_cast<size_t>(PtrDiff) <= std::numeric_limits<T>::max());
96
95.7k
  T PtrOffset = static_cast<T>(PtrDiff);
97
95.7k
98
95.7k
  // llvm::lower_bound gives the number of EOL before PtrOffset. Add 1 to get
99
95.7k
  // the line number.
100
95.7k
  return llvm::lower_bound(*Offsets, PtrOffset) - Offsets->begin() + 1;
101
95.7k
}
unsigned int llvm::SourceMgr::SrcBuffer::getLineNumber<unsigned char>(char const*) const
Line
Count
Source
72
1.02k
unsigned SourceMgr::SrcBuffer::getLineNumber(const char *Ptr) const {
73
1.02k
74
1.02k
  // Ensure OffsetCache is allocated and populated with offsets of all the
75
1.02k
  // '\n' bytes.
76
1.02k
  std::vector<T> *Offsets = nullptr;
77
1.02k
  if (OffsetCache.isNull()) {
78
837
    Offsets = new std::vector<T>();
79
837
    OffsetCache = Offsets;
80
837
    size_t Sz = Buffer->getBufferSize();
81
837
    assert(Sz <= std::numeric_limits<T>::max());
82
837
    StringRef S = Buffer->getBuffer();
83
80.2k
    for (size_t N = 0; N < Sz; 
++N79.3k
) {
84
79.3k
      if (S[N] == '\n') {
85
3.14k
        Offsets->push_back(static_cast<T>(N));
86
3.14k
      }
87
79.3k
    }
88
837
  } else {
89
189
    Offsets = OffsetCache.get<std::vector<T> *>();
90
189
  }
91
1.02k
92
1.02k
  const char *BufStart = Buffer->getBufferStart();
93
1.02k
  assert(Ptr >= BufStart && Ptr <= Buffer->getBufferEnd());
94
1.02k
  ptrdiff_t PtrDiff = Ptr - BufStart;
95
1.02k
  assert(PtrDiff >= 0 && static_cast<size_t>(PtrDiff) <= std::numeric_limits<T>::max());
96
1.02k
  T PtrOffset = static_cast<T>(PtrDiff);
97
1.02k
98
1.02k
  // llvm::lower_bound gives the number of EOL before PtrOffset. Add 1 to get
99
1.02k
  // the line number.
100
1.02k
  return llvm::lower_bound(*Offsets, PtrOffset) - Offsets->begin() + 1;
101
1.02k
}
unsigned int llvm::SourceMgr::SrcBuffer::getLineNumber<unsigned short>(char const*) const
Line
Count
Source
72
51.7k
unsigned SourceMgr::SrcBuffer::getLineNumber(const char *Ptr) const {
73
51.7k
74
51.7k
  // Ensure OffsetCache is allocated and populated with offsets of all the
75
51.7k
  // '\n' bytes.
76
51.7k
  std::vector<T> *Offsets = nullptr;
77
51.7k
  if (OffsetCache.isNull()) {
78
3.02k
    Offsets = new std::vector<T>();
79
3.02k
    OffsetCache = Offsets;
80
3.02k
    size_t Sz = Buffer->getBufferSize();
81
3.02k
    assert(Sz <= std::numeric_limits<T>::max());
82
3.02k
    StringRef S = Buffer->getBuffer();
83
13.9M
    for (size_t N = 0; N < Sz; 
++N13.9M
) {
84
13.9M
      if (S[N] == '\n') {
85
328k
        Offsets->push_back(static_cast<T>(N));
86
328k
      }
87
13.9M
    }
88
48.7k
  } else {
89
48.7k
    Offsets = OffsetCache.get<std::vector<T> *>();
90
48.7k
  }
91
51.7k
92
51.7k
  const char *BufStart = Buffer->getBufferStart();
93
51.7k
  assert(Ptr >= BufStart && Ptr <= Buffer->getBufferEnd());
94
51.7k
  ptrdiff_t PtrDiff = Ptr - BufStart;
95
51.7k
  assert(PtrDiff >= 0 && static_cast<size_t>(PtrDiff) <= std::numeric_limits<T>::max());
96
51.7k
  T PtrOffset = static_cast<T>(PtrDiff);
97
51.7k
98
51.7k
  // llvm::lower_bound gives the number of EOL before PtrOffset. Add 1 to get
99
51.7k
  // the line number.
100
51.7k
  return llvm::lower_bound(*Offsets, PtrOffset) - Offsets->begin() + 1;
101
51.7k
}
unsigned int llvm::SourceMgr::SrcBuffer::getLineNumber<unsigned int>(char const*) const
Line
Count
Source
72
43.0k
unsigned SourceMgr::SrcBuffer::getLineNumber(const char *Ptr) const {
73
43.0k
74
43.0k
  // Ensure OffsetCache is allocated and populated with offsets of all the
75
43.0k
  // '\n' bytes.
76
43.0k
  std::vector<T> *Offsets = nullptr;
77
43.0k
  if (OffsetCache.isNull()) {
78
25
    Offsets = new std::vector<T>();
79
25
    OffsetCache = Offsets;
80
25
    size_t Sz = Buffer->getBufferSize();
81
25
    assert(Sz <= std::numeric_limits<T>::max());
82
25
    StringRef S = Buffer->getBuffer();
83
22.5M
    for (size_t N = 0; N < Sz; 
++N22.5M
) {
84
22.5M
      if (S[N] == '\n') {
85
623k
        Offsets->push_back(static_cast<T>(N));
86
623k
      }
87
22.5M
    }
88
42.9k
  } else {
89
42.9k
    Offsets = OffsetCache.get<std::vector<T> *>();
90
42.9k
  }
91
43.0k
92
43.0k
  const char *BufStart = Buffer->getBufferStart();
93
43.0k
  assert(Ptr >= BufStart && Ptr <= Buffer->getBufferEnd());
94
43.0k
  ptrdiff_t PtrDiff = Ptr - BufStart;
95
43.0k
  assert(PtrDiff >= 0 && static_cast<size_t>(PtrDiff) <= std::numeric_limits<T>::max());
96
43.0k
  T PtrOffset = static_cast<T>(PtrDiff);
97
43.0k
98
43.0k
  // llvm::lower_bound gives the number of EOL before PtrOffset. Add 1 to get
99
43.0k
  // the line number.
100
43.0k
  return llvm::lower_bound(*Offsets, PtrOffset) - Offsets->begin() + 1;
101
43.0k
}
Unexecuted instantiation: unsigned int llvm::SourceMgr::SrcBuffer::getLineNumber<unsigned long long>(char const*) const
102
103
SourceMgr::SrcBuffer::SrcBuffer(SourceMgr::SrcBuffer &&Other)
104
  : Buffer(std::move(Other.Buffer)),
105
    OffsetCache(Other.OffsetCache),
106
536k
    IncludeLoc(Other.IncludeLoc) {
107
536k
  Other.OffsetCache = nullptr;
108
536k
}
109
110
842k
SourceMgr::SrcBuffer::~SrcBuffer() {
111
842k
  if (!OffsetCache.isNull()) {
112
3.86k
    if (OffsetCache.is<std::vector<uint8_t>*>())
113
830
      delete OffsetCache.get<std::vector<uint8_t>*>();
114
3.03k
    else if (OffsetCache.is<std::vector<uint16_t>*>())
115
3.01k
      delete OffsetCache.get<std::vector<uint16_t>*>();
116
25
    else if (OffsetCache.is<std::vector<uint32_t>*>())
117
25
      delete OffsetCache.get<std::vector<uint32_t>*>();
118
0
    else
119
0
      delete OffsetCache.get<std::vector<uint64_t>*>();
120
3.86k
    OffsetCache = nullptr;
121
3.86k
  }
122
842k
}
123
124
std::pair<unsigned, unsigned>
125
95.7k
SourceMgr::getLineAndColumn(SMLoc Loc, unsigned BufferID) const {
126
95.7k
  if (!BufferID)
127
108
    BufferID = FindBufferContainingLoc(Loc);
128
95.7k
  assert(BufferID && "Invalid Location!");
129
95.7k
130
95.7k
  auto &SB = getBufferInfo(BufferID);
131
95.7k
  const char *Ptr = Loc.getPointer();
132
95.7k
133
95.7k
  size_t Sz = SB.Buffer->getBufferSize();
134
95.7k
  unsigned LineNo;
135
95.7k
  if (Sz <= std::numeric_limits<uint8_t>::max())
136
1.02k
    LineNo = SB.getLineNumber<uint8_t>(Ptr);
137
94.7k
  else if (Sz <= std::numeric_limits<uint16_t>::max())
138
51.7k
    LineNo = SB.getLineNumber<uint16_t>(Ptr);
139
43.0k
  else if (Sz <= std::numeric_limits<uint32_t>::max())
140
43.0k
    LineNo = SB.getLineNumber<uint32_t>(Ptr);
141
0
  else
142
0
    LineNo = SB.getLineNumber<uint64_t>(Ptr);
143
95.7k
144
95.7k
  const char *BufStart = SB.Buffer->getBufferStart();
145
95.7k
  size_t NewlineOffs = StringRef(BufStart, Ptr-BufStart).find_last_of("\n\r");
146
95.7k
  if (NewlineOffs == StringRef::npos) 
NewlineOffs = ~(size_t)0479
;
147
95.7k
  return std::make_pair(LineNo, Ptr-BufStart-NewlineOffs);
148
95.7k
}
149
150
4.94k
void SourceMgr::PrintIncludeStack(SMLoc IncludeLoc, raw_ostream &OS) const {
151
4.94k
  if (IncludeLoc == SMLoc()) 
return4.93k
; // Top of stack.
152
10
153
10
  unsigned CurBuf = FindBufferContainingLoc(IncludeLoc);
154
10
  assert(CurBuf && "Invalid or unspecified location!");
155
10
156
10
  PrintIncludeStack(getBufferInfo(CurBuf).IncludeLoc, OS);
157
10
158
10
  OS << "Included from "
159
10
     << getBufferInfo(CurBuf).Buffer->getBufferIdentifier()
160
10
     << ":" << FindLineNumber(IncludeLoc, CurBuf) << ":\n";
161
10
}
162
163
SMDiagnostic SourceMgr::GetMessage(SMLoc Loc, SourceMgr::DiagKind Kind,
164
                                   const Twine &Msg,
165
                                   ArrayRef<SMRange> Ranges,
166
93.1k
                                   ArrayRef<SMFixIt> FixIts) const {
167
93.1k
  // First thing to do: find the current buffer containing the specified
168
93.1k
  // location to pull out the source line.
169
93.1k
  SmallVector<std::pair<unsigned, unsigned>, 4> ColRanges;
170
93.1k
  std::pair<unsigned, unsigned> LineAndCol;
171
93.1k
  StringRef BufferID = "<unknown>";
172
93.1k
  std::string LineStr;
173
93.1k
174
93.1k
  if (Loc.isValid()) {
175
92.9k
    unsigned CurBuf = FindBufferContainingLoc(Loc);
176
92.9k
    assert(CurBuf && "Invalid or unspecified location!");
177
92.9k
178
92.9k
    const MemoryBuffer *CurMB = getMemoryBuffer(CurBuf);
179
92.9k
    BufferID = CurMB->getBufferIdentifier();
180
92.9k
181
92.9k
    // Scan backward to find the start of the line.
182
92.9k
    const char *LineStart = Loc.getPointer();
183
92.9k
    const char *BufStart = CurMB->getBufferStart();
184
1.09M
    while (LineStart != BufStart && 
LineStart[-1] != '\n'1.08M
&&
185
1.09M
           
LineStart[-1] != '\r'997k
)
186
997k
      --LineStart;
187
92.9k
188
92.9k
    // Get the end of the line.
189
92.9k
    const char *LineEnd = Loc.getPointer();
190
92.9k
    const char *BufEnd = CurMB->getBufferEnd();
191
2.43M
    while (LineEnd != BufEnd && 
LineEnd[0] != '\n'2.43M
&&
LineEnd[0] != '\r'2.33M
)
192
2.33M
      ++LineEnd;
193
92.9k
    LineStr = std::string(LineStart, LineEnd);
194
92.9k
195
92.9k
    // Convert any ranges to column ranges that only intersect the line of the
196
92.9k
    // location.
197
180k
    for (unsigned i = 0, e = Ranges.size(); i != e; 
++i87.1k
) {
198
87.1k
      SMRange R = Ranges[i];
199
87.1k
      if (!R.isValid()) 
continue86.6k
;
200
507
201
507
      // If the line doesn't contain any part of the range, then ignore it.
202
507
      if (R.Start.getPointer() > LineEnd || R.End.getPointer() < LineStart)
203
0
        continue;
204
507
205
507
      // Ignore pieces of the range that go onto other lines.
206
507
      if (R.Start.getPointer() < LineStart)
207
0
        R.Start = SMLoc::getFromPointer(LineStart);
208
507
      if (R.End.getPointer() > LineEnd)
209
70
        R.End = SMLoc::getFromPointer(LineEnd);
210
507
211
507
      // Translate from SMLoc ranges to column ranges.
212
507
      // FIXME: Handle multibyte characters.
213
507
      ColRanges.push_back(std::make_pair(R.Start.getPointer()-LineStart,
214
507
                                         R.End.getPointer()-LineStart));
215
507
    }
216
92.9k
217
92.9k
    LineAndCol = getLineAndColumn(Loc, CurBuf);
218
92.9k
  }
219
93.1k
220
93.1k
  return SMDiagnostic(*this, Loc, BufferID, LineAndCol.first,
221
93.1k
                      LineAndCol.second-1, Kind, Msg.str(),
222
93.1k
                      LineStr, ColRanges, FixIts);
223
93.1k
}
224
225
void SourceMgr::PrintMessage(raw_ostream &OS, const SMDiagnostic &Diagnostic,
226
92.6k
                             bool ShowColors) const {
227
92.6k
  // Report the message with the diagnostic handler if present.
228
92.6k
  if (DiagHandler) {
229
87.8k
    DiagHandler(Diagnostic, DiagContext);
230
87.8k
    return;
231
87.8k
  }
232
4.89k
233
4.89k
  if (Diagnostic.getLoc().isValid()) {
234
4.89k
    unsigned CurBuf = FindBufferContainingLoc(Diagnostic.getLoc());
235
4.89k
    assert(CurBuf && "Invalid or unspecified location!");
236
4.89k
    PrintIncludeStack(getBufferInfo(CurBuf).IncludeLoc, OS);
237
4.89k
  }
238
4.89k
239
4.89k
  Diagnostic.print(nullptr, OS, ShowColors);
240
4.89k
}
241
242
void SourceMgr::PrintMessage(raw_ostream &OS, SMLoc Loc,
243
                             SourceMgr::DiagKind Kind,
244
                             const Twine &Msg, ArrayRef<SMRange> Ranges,
245
92.6k
                             ArrayRef<SMFixIt> FixIts, bool ShowColors) const {
246
92.6k
  PrintMessage(OS, GetMessage(Loc, Kind, Msg, Ranges, FixIts), ShowColors);
247
92.6k
}
248
249
void SourceMgr::PrintMessage(SMLoc Loc, SourceMgr::DiagKind Kind,
250
                             const Twine &Msg, ArrayRef<SMRange> Ranges,
251
92.6k
                             ArrayRef<SMFixIt> FixIts, bool ShowColors) const {
252
92.6k
  PrintMessage(errs(), Loc, Kind, Msg, Ranges, FixIts, ShowColors);
253
92.6k
}
254
255
//===----------------------------------------------------------------------===//
256
// SMDiagnostic Implementation
257
//===----------------------------------------------------------------------===//
258
259
SMDiagnostic::SMDiagnostic(const SourceMgr &sm, SMLoc L, StringRef FN,
260
                           int Line, int Col, SourceMgr::DiagKind Kind,
261
                           StringRef Msg, StringRef LineStr,
262
                           ArrayRef<std::pair<unsigned,unsigned>> Ranges,
263
                           ArrayRef<SMFixIt> Hints)
264
  : SM(&sm), Loc(L), Filename(FN), LineNo(Line), ColumnNo(Col), Kind(Kind),
265
    Message(Msg), LineContents(LineStr), Ranges(Ranges.vec()),
266
93.3k
    FixIts(Hints.begin(), Hints.end()) {
267
93.3k
  llvm::sort(FixIts);
268
93.3k
}
269
270
static void buildFixItLine(std::string &CaretLine, std::string &FixItLine,
271
93.0k
                           ArrayRef<SMFixIt> FixIts, ArrayRef<char> SourceLine){
272
93.0k
  if (FixIts.empty())
273
92.9k
    return;
274
23
275
23
  const char *LineStart = SourceLine.begin();
276
23
  const char *LineEnd = SourceLine.end();
277
23
278
23
  size_t PrevHintEndCol = 0;
279
23
280
23
  for (ArrayRef<SMFixIt>::iterator I = FixIts.begin(), E = FixIts.end();
281
46
       I != E; 
++I23
) {
282
23
    // If the fixit contains a newline or tab, ignore it.
283
23
    if (I->getText().find_first_of("\n\r\t") != StringRef::npos)
284
0
      continue;
285
23
286
23
    SMRange R = I->getRange();
287
23
288
23
    // If the line doesn't contain any part of the range, then ignore it.
289
23
    if (R.Start.getPointer() > LineEnd || R.End.getPointer() < LineStart)
290
0
      continue;
291
23
292
23
    // Translate from SMLoc to column.
293
23
    // Ignore pieces of the range that go onto other lines.
294
23
    // FIXME: Handle multibyte characters in the source line.
295
23
    unsigned FirstCol;
296
23
    if (R.Start.getPointer() < LineStart)
297
0
      FirstCol = 0;
298
23
    else
299
23
      FirstCol = R.Start.getPointer() - LineStart;
300
23
301
23
    // If we inserted a long previous hint, push this one forwards, and add
302
23
    // an extra space to show that this is not part of the previous
303
23
    // completion. This is sort of the best we can do when two hints appear
304
23
    // to overlap.
305
23
    //
306
23
    // Note that if this hint is located immediately after the previous
307
23
    // hint, no space will be added, since the location is more important.
308
23
    unsigned HintCol = FirstCol;
309
23
    if (HintCol < PrevHintEndCol)
310
0
      HintCol = PrevHintEndCol + 1;
311
23
312
23
    // FIXME: This assertion is intended to catch unintended use of multibyte
313
23
    // characters in fixits. If we decide to do this, we'll have to track
314
23
    // separate byte widths for the source and fixit lines.
315
23
    assert((size_t)sys::locale::columnWidth(I->getText()) ==
316
23
           I->getText().size());
317
23
318
23
    // This relies on one byte per column in our fixit hints.
319
23
    unsigned LastColumnModified = HintCol + I->getText().size();
320
23
    if (LastColumnModified > FixItLine.size())
321
23
      FixItLine.resize(LastColumnModified, ' ');
322
23
323
23
    std::copy(I->getText().begin(), I->getText().end(),
324
23
              FixItLine.begin() + HintCol);
325
23
326
23
    PrevHintEndCol = LastColumnModified;
327
23
328
23
    // For replacements, mark the removal range with '~'.
329
23
    // FIXME: Handle multibyte characters in the source line.
330
23
    unsigned LastCol;
331
23
    if (R.End.getPointer() >= LineEnd)
332
1
      LastCol = LineEnd - LineStart;
333
22
    else
334
22
      LastCol = R.End.getPointer() - LineStart;
335
23
336
23
    std::fill(&CaretLine[FirstCol], &CaretLine[LastCol], '~');
337
23
  }
338
23
}
339
340
93.0k
static void printSourceLine(raw_ostream &S, StringRef LineContents) {
341
93.0k
  // Print out the source line one character at a time, so we can expand tabs.
342
117k
  for (unsigned i = 0, e = LineContents.size(), OutCol = 0; i != e; 
++i24.9k
) {
343
117k
    size_t NextTab = LineContents.find('\t', i);
344
117k
    // If there were no tabs left, print the rest, we are done.
345
117k
    if (NextTab == StringRef::npos) {
346
92.7k
      S << LineContents.drop_front(i);
347
92.7k
      break;
348
92.7k
    }
349
24.9k
350
24.9k
    // Otherwise, print from i to NextTab.
351
24.9k
    S << LineContents.slice(i, NextTab);
352
24.9k
    OutCol += NextTab - i;
353
24.9k
    i = NextTab;
354
24.9k
355
24.9k
    // If we have a tab, emit at least one space, then round up to 8 columns.
356
143k
    do {
357
143k
      S << ' ';
358
143k
      ++OutCol;
359
143k
    } while ((OutCol % TabStop) != 0);
360
24.9k
  }
361
93.0k
  S << '\n';
362
93.0k
}
363
364
3.33M
static bool isNonASCII(char c) {
365
3.33M
  return c & 0x80;
366
3.33M
}
367
368
void SMDiagnostic::print(const char *ProgName, raw_ostream &OS,
369
93.1k
                         bool ShowColors, bool ShowKindLabel) const {
370
93.1k
  {
371
93.1k
    WithColor S(OS, raw_ostream::SAVEDCOLOR, true, false, !ShowColors);
372
93.1k
373
93.1k
    if (ProgName && 
ProgName[0]561
)
374
220
      S << ProgName << ": ";
375
93.1k
376
93.1k
    if (!Filename.empty()) {
377
92.9k
      if (Filename == "-")
378
0
        S << "<stdin>";
379
92.9k
      else
380
92.9k
        S << Filename;
381
92.9k
382
92.9k
      if (LineNo != -1) {
383
92.9k
        S << ':' << LineNo;
384
92.9k
        if (ColumnNo != -1)
385
92.8k
          S << ':' << (ColumnNo + 1);
386
92.9k
      }
387
92.9k
      S << ": ";
388
92.9k
    }
389
93.1k
  }
390
93.1k
391
93.1k
  if (ShowKindLabel) {
392
92.9k
    switch (Kind) {
393
92.9k
    case SourceMgr::DK_Error:
394
81.4k
      WithColor::error(OS, "", !ShowColors);
395
81.4k
      break;
396
92.9k
    case SourceMgr::DK_Warning:
397
7.76k
      WithColor::warning(OS, "", !ShowColors);
398
7.76k
      break;
399
92.9k
    case SourceMgr::DK_Note:
400
3.81k
      WithColor::note(OS, "", !ShowColors);
401
3.81k
      break;
402
92.9k
    case SourceMgr::DK_Remark:
403
1
      WithColor::remark(OS, "", !ShowColors);
404
1
      break;
405
93.1k
    }
406
93.1k
  }
407
93.1k
408
93.1k
  WithColor(OS, raw_ostream::SAVEDCOLOR, true, false, !ShowColors)
409
93.1k
      << Message << '\n';
410
93.1k
411
93.1k
  if (LineNo == -1 || 
ColumnNo == -193.1k
)
412
130
    return;
413
93.0k
414
93.0k
  // FIXME: If there are multibyte or multi-column characters in the source, all
415
93.0k
  // our ranges will be wrong. To do this properly, we'll need a byte-to-column
416
93.0k
  // map like Clang's TextDiagnostic. For now, we'll just handle tabs by
417
93.0k
  // expanding them later, and bail out rather than show incorrect ranges and
418
93.0k
  // misaligned fixits for any other odd characters.
419
93.0k
  if (find_if(LineContents, isNonASCII) != LineContents.end()) {
420
4
    printSourceLine(OS, LineContents);
421
4
    return;
422
4
  }
423
93.0k
  size_t NumColumns = LineContents.size();
424
93.0k
425
93.0k
  // Build the line with the caret and ranges.
426
93.0k
  std::string CaretLine(NumColumns+1, ' ');
427
93.0k
428
93.0k
  // Expand any ranges.
429
93.4k
  for (unsigned r = 0, e = Ranges.size(); r != e; 
++r451
) {
430
451
    std::pair<unsigned, unsigned> R = Ranges[r];
431
451
    std::fill(&CaretLine[R.first],
432
451
              &CaretLine[std::min((size_t)R.second, CaretLine.size())],
433
451
              '~');
434
451
  }
435
93.0k
436
93.0k
  // Add any fix-its.
437
93.0k
  // FIXME: Find the beginning of the line properly for multibyte characters.
438
93.0k
  std::string FixItInsertionLine;
439
93.0k
  buildFixItLine(CaretLine, FixItInsertionLine, FixIts,
440
93.0k
                 makeArrayRef(Loc.getPointer() - ColumnNo,
441
93.0k
                              LineContents.size()));
442
93.0k
443
93.0k
  // Finally, plop on the caret.
444
93.0k
  if (unsigned(ColumnNo) <= NumColumns)
445
93.0k
    CaretLine[ColumnNo] = '^';
446
0
  else
447
0
    CaretLine[NumColumns] = '^';
448
93.0k
449
93.0k
  // ... and remove trailing whitespace so the output doesn't wrap for it.  We
450
93.0k
  // know that the line isn't completely empty because it has the caret in it at
451
93.0k
  // least.
452
93.0k
  CaretLine.erase(CaretLine.find_last_not_of(' ')+1);
453
93.0k
454
93.0k
  printSourceLine(OS, LineContents);
455
93.0k
456
93.0k
  {
457
93.0k
    WithColor S(OS, raw_ostream::GREEN, true, false, !ShowColors);
458
93.0k
459
93.0k
    // Print out the caret line, matching tabs in the source line.
460
1.18M
    for (unsigned i = 0, e = CaretLine.size(), OutCol = 0; i != e; 
++i1.08M
) {
461
1.08M
      if (i >= LineContents.size() || 
LineContents[i] != '\t'1.08M
) {
462
1.06M
        S << CaretLine[i];
463
1.06M
        ++OutCol;
464
1.06M
        continue;
465
1.06M
      }
466
22.3k
467
22.3k
      // Okay, we have a tab.  Insert the appropriate number of characters.
468
137k
      
do 22.3k
{
469
137k
        S << CaretLine[i];
470
137k
        ++OutCol;
471
137k
      } while ((OutCol % TabStop) != 0);
472
22.3k
    }
473
93.0k
    S << '\n';
474
93.0k
  }
475
93.0k
476
93.0k
  // Print out the replacement line, matching tabs in the source line.
477
93.0k
  if (FixItInsertionLine.empty())
478
92.9k
    return;
479
23
480
696
  
for (size_t i = 0, e = FixItInsertionLine.size(), OutCol = 0; 23
i < e;
++i673
) {
481
673
    if (i >= LineContents.size() || LineContents[i] != '\t') {
482
658
      OS << FixItInsertionLine[i];
483
658
      ++OutCol;
484
658
      continue;
485
658
    }
486
15
487
15
    // Okay, we have a tab.  Insert the appropriate number of characters.
488
55
    
do 15
{
489
55
      OS << FixItInsertionLine[i];
490
55
      // FIXME: This is trying not to break up replacements, but then to re-sync
491
55
      // with the tabs between replacements. This will fail, though, if two
492
55
      // fix-it replacements are exactly adjacent, or if a fix-it contains a
493
55
      // space. Really we should be precomputing column widths, which we'll
494
55
      // need anyway for multibyte chars.
495
55
      if (FixItInsertionLine[i] != ' ')
496
3
        ++i;
497
55
      ++OutCol;
498
55
    } while (((OutCol % TabStop) != 0) && 
i != e41
);
499
15
  }
500
23
  OS << '\n';
501
23
}