1*67e74705SXin Li //===--- TextDiagnostic.cpp - Text Diagnostic Pretty-Printing -------------===//
2*67e74705SXin Li //
3*67e74705SXin Li // The LLVM Compiler Infrastructure
4*67e74705SXin Li //
5*67e74705SXin Li // This file is distributed under the University of Illinois Open Source
6*67e74705SXin Li // License. See LICENSE.TXT for details.
7*67e74705SXin Li //
8*67e74705SXin Li //===----------------------------------------------------------------------===//
9*67e74705SXin Li
10*67e74705SXin Li #include "clang/Frontend/TextDiagnostic.h"
11*67e74705SXin Li #include "clang/Basic/CharInfo.h"
12*67e74705SXin Li #include "clang/Basic/DiagnosticOptions.h"
13*67e74705SXin Li #include "clang/Basic/FileManager.h"
14*67e74705SXin Li #include "clang/Basic/SourceManager.h"
15*67e74705SXin Li #include "clang/Lex/Lexer.h"
16*67e74705SXin Li #include "llvm/ADT/SmallString.h"
17*67e74705SXin Li #include "llvm/ADT/StringExtras.h"
18*67e74705SXin Li #include "llvm/Support/ConvertUTF.h"
19*67e74705SXin Li #include "llvm/Support/ErrorHandling.h"
20*67e74705SXin Li #include "llvm/Support/Locale.h"
21*67e74705SXin Li #include "llvm/Support/MemoryBuffer.h"
22*67e74705SXin Li #include "llvm/Support/raw_ostream.h"
23*67e74705SXin Li #include <algorithm>
24*67e74705SXin Li
25*67e74705SXin Li using namespace clang;
26*67e74705SXin Li
27*67e74705SXin Li static const enum raw_ostream::Colors noteColor =
28*67e74705SXin Li raw_ostream::BLACK;
29*67e74705SXin Li static const enum raw_ostream::Colors remarkColor =
30*67e74705SXin Li raw_ostream::BLUE;
31*67e74705SXin Li static const enum raw_ostream::Colors fixitColor =
32*67e74705SXin Li raw_ostream::GREEN;
33*67e74705SXin Li static const enum raw_ostream::Colors caretColor =
34*67e74705SXin Li raw_ostream::GREEN;
35*67e74705SXin Li static const enum raw_ostream::Colors warningColor =
36*67e74705SXin Li raw_ostream::MAGENTA;
37*67e74705SXin Li static const enum raw_ostream::Colors templateColor =
38*67e74705SXin Li raw_ostream::CYAN;
39*67e74705SXin Li static const enum raw_ostream::Colors errorColor = raw_ostream::RED;
40*67e74705SXin Li static const enum raw_ostream::Colors fatalColor = raw_ostream::RED;
41*67e74705SXin Li // Used for changing only the bold attribute.
42*67e74705SXin Li static const enum raw_ostream::Colors savedColor =
43*67e74705SXin Li raw_ostream::SAVEDCOLOR;
44*67e74705SXin Li
45*67e74705SXin Li /// \brief Add highlights to differences in template strings.
applyTemplateHighlighting(raw_ostream & OS,StringRef Str,bool & Normal,bool Bold)46*67e74705SXin Li static void applyTemplateHighlighting(raw_ostream &OS, StringRef Str,
47*67e74705SXin Li bool &Normal, bool Bold) {
48*67e74705SXin Li while (1) {
49*67e74705SXin Li size_t Pos = Str.find(ToggleHighlight);
50*67e74705SXin Li OS << Str.slice(0, Pos);
51*67e74705SXin Li if (Pos == StringRef::npos)
52*67e74705SXin Li break;
53*67e74705SXin Li
54*67e74705SXin Li Str = Str.substr(Pos + 1);
55*67e74705SXin Li if (Normal)
56*67e74705SXin Li OS.changeColor(templateColor, true);
57*67e74705SXin Li else {
58*67e74705SXin Li OS.resetColor();
59*67e74705SXin Li if (Bold)
60*67e74705SXin Li OS.changeColor(savedColor, true);
61*67e74705SXin Li }
62*67e74705SXin Li Normal = !Normal;
63*67e74705SXin Li }
64*67e74705SXin Li }
65*67e74705SXin Li
66*67e74705SXin Li /// \brief Number of spaces to indent when word-wrapping.
67*67e74705SXin Li const unsigned WordWrapIndentation = 6;
68*67e74705SXin Li
bytesSincePreviousTabOrLineBegin(StringRef SourceLine,size_t i)69*67e74705SXin Li static int bytesSincePreviousTabOrLineBegin(StringRef SourceLine, size_t i) {
70*67e74705SXin Li int bytes = 0;
71*67e74705SXin Li while (0<i) {
72*67e74705SXin Li if (SourceLine[--i]=='\t')
73*67e74705SXin Li break;
74*67e74705SXin Li ++bytes;
75*67e74705SXin Li }
76*67e74705SXin Li return bytes;
77*67e74705SXin Li }
78*67e74705SXin Li
79*67e74705SXin Li /// \brief returns a printable representation of first item from input range
80*67e74705SXin Li ///
81*67e74705SXin Li /// This function returns a printable representation of the next item in a line
82*67e74705SXin Li /// of source. If the next byte begins a valid and printable character, that
83*67e74705SXin Li /// character is returned along with 'true'.
84*67e74705SXin Li ///
85*67e74705SXin Li /// Otherwise, if the next byte begins a valid, but unprintable character, a
86*67e74705SXin Li /// printable, escaped representation of the character is returned, along with
87*67e74705SXin Li /// 'false'. Otherwise a printable, escaped representation of the next byte
88*67e74705SXin Li /// is returned along with 'false'.
89*67e74705SXin Li ///
90*67e74705SXin Li /// \note The index is updated to be used with a subsequent call to
91*67e74705SXin Li /// printableTextForNextCharacter.
92*67e74705SXin Li ///
93*67e74705SXin Li /// \param SourceLine The line of source
94*67e74705SXin Li /// \param i Pointer to byte index,
95*67e74705SXin Li /// \param TabStop used to expand tabs
96*67e74705SXin Li /// \return pair(printable text, 'true' iff original text was printable)
97*67e74705SXin Li ///
98*67e74705SXin Li static std::pair<SmallString<16>, bool>
printableTextForNextCharacter(StringRef SourceLine,size_t * i,unsigned TabStop)99*67e74705SXin Li printableTextForNextCharacter(StringRef SourceLine, size_t *i,
100*67e74705SXin Li unsigned TabStop) {
101*67e74705SXin Li assert(i && "i must not be null");
102*67e74705SXin Li assert(*i<SourceLine.size() && "must point to a valid index");
103*67e74705SXin Li
104*67e74705SXin Li if (SourceLine[*i]=='\t') {
105*67e74705SXin Li assert(0 < TabStop && TabStop <= DiagnosticOptions::MaxTabStop &&
106*67e74705SXin Li "Invalid -ftabstop value");
107*67e74705SXin Li unsigned col = bytesSincePreviousTabOrLineBegin(SourceLine, *i);
108*67e74705SXin Li unsigned NumSpaces = TabStop - col%TabStop;
109*67e74705SXin Li assert(0 < NumSpaces && NumSpaces <= TabStop
110*67e74705SXin Li && "Invalid computation of space amt");
111*67e74705SXin Li ++(*i);
112*67e74705SXin Li
113*67e74705SXin Li SmallString<16> expandedTab;
114*67e74705SXin Li expandedTab.assign(NumSpaces, ' ');
115*67e74705SXin Li return std::make_pair(expandedTab, true);
116*67e74705SXin Li }
117*67e74705SXin Li
118*67e74705SXin Li unsigned char const *begin, *end;
119*67e74705SXin Li begin = reinterpret_cast<unsigned char const *>(&*(SourceLine.begin() + *i));
120*67e74705SXin Li end = begin + (SourceLine.size() - *i);
121*67e74705SXin Li
122*67e74705SXin Li if (isLegalUTF8Sequence(begin, end)) {
123*67e74705SXin Li UTF32 c;
124*67e74705SXin Li UTF32 *cptr = &c;
125*67e74705SXin Li unsigned char const *original_begin = begin;
126*67e74705SXin Li unsigned char const *cp_end = begin+getNumBytesForUTF8(SourceLine[*i]);
127*67e74705SXin Li
128*67e74705SXin Li ConversionResult res = ConvertUTF8toUTF32(&begin, cp_end, &cptr, cptr+1,
129*67e74705SXin Li strictConversion);
130*67e74705SXin Li (void)res;
131*67e74705SXin Li assert(conversionOK==res);
132*67e74705SXin Li assert(0 < begin-original_begin
133*67e74705SXin Li && "we must be further along in the string now");
134*67e74705SXin Li *i += begin-original_begin;
135*67e74705SXin Li
136*67e74705SXin Li if (!llvm::sys::locale::isPrint(c)) {
137*67e74705SXin Li // If next character is valid UTF-8, but not printable
138*67e74705SXin Li SmallString<16> expandedCP("<U+>");
139*67e74705SXin Li while (c) {
140*67e74705SXin Li expandedCP.insert(expandedCP.begin()+3, llvm::hexdigit(c%16));
141*67e74705SXin Li c/=16;
142*67e74705SXin Li }
143*67e74705SXin Li while (expandedCP.size() < 8)
144*67e74705SXin Li expandedCP.insert(expandedCP.begin()+3, llvm::hexdigit(0));
145*67e74705SXin Li return std::make_pair(expandedCP, false);
146*67e74705SXin Li }
147*67e74705SXin Li
148*67e74705SXin Li // If next character is valid UTF-8, and printable
149*67e74705SXin Li return std::make_pair(SmallString<16>(original_begin, cp_end), true);
150*67e74705SXin Li
151*67e74705SXin Li }
152*67e74705SXin Li
153*67e74705SXin Li // If next byte is not valid UTF-8 (and therefore not printable)
154*67e74705SXin Li SmallString<16> expandedByte("<XX>");
155*67e74705SXin Li unsigned char byte = SourceLine[*i];
156*67e74705SXin Li expandedByte[1] = llvm::hexdigit(byte / 16);
157*67e74705SXin Li expandedByte[2] = llvm::hexdigit(byte % 16);
158*67e74705SXin Li ++(*i);
159*67e74705SXin Li return std::make_pair(expandedByte, false);
160*67e74705SXin Li }
161*67e74705SXin Li
expandTabs(std::string & SourceLine,unsigned TabStop)162*67e74705SXin Li static void expandTabs(std::string &SourceLine, unsigned TabStop) {
163*67e74705SXin Li size_t i = SourceLine.size();
164*67e74705SXin Li while (i>0) {
165*67e74705SXin Li i--;
166*67e74705SXin Li if (SourceLine[i]!='\t')
167*67e74705SXin Li continue;
168*67e74705SXin Li size_t tmp_i = i;
169*67e74705SXin Li std::pair<SmallString<16>,bool> res
170*67e74705SXin Li = printableTextForNextCharacter(SourceLine, &tmp_i, TabStop);
171*67e74705SXin Li SourceLine.replace(i, 1, res.first.c_str());
172*67e74705SXin Li }
173*67e74705SXin Li }
174*67e74705SXin Li
175*67e74705SXin Li /// This function takes a raw source line and produces a mapping from the bytes
176*67e74705SXin Li /// of the printable representation of the line to the columns those printable
177*67e74705SXin Li /// characters will appear at (numbering the first column as 0).
178*67e74705SXin Li ///
179*67e74705SXin Li /// If a byte 'i' corresponds to multiple columns (e.g. the byte contains a tab
180*67e74705SXin Li /// character) then the array will map that byte to the first column the
181*67e74705SXin Li /// tab appears at and the next value in the map will have been incremented
182*67e74705SXin Li /// more than once.
183*67e74705SXin Li ///
184*67e74705SXin Li /// If a byte is the first in a sequence of bytes that together map to a single
185*67e74705SXin Li /// entity in the output, then the array will map that byte to the appropriate
186*67e74705SXin Li /// column while the subsequent bytes will be -1.
187*67e74705SXin Li ///
188*67e74705SXin Li /// The last element in the array does not correspond to any byte in the input
189*67e74705SXin Li /// and instead is the number of columns needed to display the source
190*67e74705SXin Li ///
191*67e74705SXin Li /// example: (given a tabstop of 8)
192*67e74705SXin Li ///
193*67e74705SXin Li /// "a \t \u3042" -> {0,1,2,8,9,-1,-1,11}
194*67e74705SXin Li ///
195*67e74705SXin Li /// (\\u3042 is represented in UTF-8 by three bytes and takes two columns to
196*67e74705SXin Li /// display)
byteToColumn(StringRef SourceLine,unsigned TabStop,SmallVectorImpl<int> & out)197*67e74705SXin Li static void byteToColumn(StringRef SourceLine, unsigned TabStop,
198*67e74705SXin Li SmallVectorImpl<int> &out) {
199*67e74705SXin Li out.clear();
200*67e74705SXin Li
201*67e74705SXin Li if (SourceLine.empty()) {
202*67e74705SXin Li out.resize(1u,0);
203*67e74705SXin Li return;
204*67e74705SXin Li }
205*67e74705SXin Li
206*67e74705SXin Li out.resize(SourceLine.size()+1, -1);
207*67e74705SXin Li
208*67e74705SXin Li int columns = 0;
209*67e74705SXin Li size_t i = 0;
210*67e74705SXin Li while (i<SourceLine.size()) {
211*67e74705SXin Li out[i] = columns;
212*67e74705SXin Li std::pair<SmallString<16>,bool> res
213*67e74705SXin Li = printableTextForNextCharacter(SourceLine, &i, TabStop);
214*67e74705SXin Li columns += llvm::sys::locale::columnWidth(res.first);
215*67e74705SXin Li }
216*67e74705SXin Li out.back() = columns;
217*67e74705SXin Li }
218*67e74705SXin Li
219*67e74705SXin Li /// This function takes a raw source line and produces a mapping from columns
220*67e74705SXin Li /// to the byte of the source line that produced the character displaying at
221*67e74705SXin Li /// that column. This is the inverse of the mapping produced by byteToColumn()
222*67e74705SXin Li ///
223*67e74705SXin Li /// The last element in the array is the number of bytes in the source string
224*67e74705SXin Li ///
225*67e74705SXin Li /// example: (given a tabstop of 8)
226*67e74705SXin Li ///
227*67e74705SXin Li /// "a \t \u3042" -> {0,1,2,-1,-1,-1,-1,-1,3,4,-1,7}
228*67e74705SXin Li ///
229*67e74705SXin Li /// (\\u3042 is represented in UTF-8 by three bytes and takes two columns to
230*67e74705SXin Li /// display)
columnToByte(StringRef SourceLine,unsigned TabStop,SmallVectorImpl<int> & out)231*67e74705SXin Li static void columnToByte(StringRef SourceLine, unsigned TabStop,
232*67e74705SXin Li SmallVectorImpl<int> &out) {
233*67e74705SXin Li out.clear();
234*67e74705SXin Li
235*67e74705SXin Li if (SourceLine.empty()) {
236*67e74705SXin Li out.resize(1u, 0);
237*67e74705SXin Li return;
238*67e74705SXin Li }
239*67e74705SXin Li
240*67e74705SXin Li int columns = 0;
241*67e74705SXin Li size_t i = 0;
242*67e74705SXin Li while (i<SourceLine.size()) {
243*67e74705SXin Li out.resize(columns+1, -1);
244*67e74705SXin Li out.back() = i;
245*67e74705SXin Li std::pair<SmallString<16>,bool> res
246*67e74705SXin Li = printableTextForNextCharacter(SourceLine, &i, TabStop);
247*67e74705SXin Li columns += llvm::sys::locale::columnWidth(res.first);
248*67e74705SXin Li }
249*67e74705SXin Li out.resize(columns+1, -1);
250*67e74705SXin Li out.back() = i;
251*67e74705SXin Li }
252*67e74705SXin Li
253*67e74705SXin Li namespace {
254*67e74705SXin Li struct SourceColumnMap {
SourceColumnMap__anon3e7c482b0111::SourceColumnMap255*67e74705SXin Li SourceColumnMap(StringRef SourceLine, unsigned TabStop)
256*67e74705SXin Li : m_SourceLine(SourceLine) {
257*67e74705SXin Li
258*67e74705SXin Li ::byteToColumn(SourceLine, TabStop, m_byteToColumn);
259*67e74705SXin Li ::columnToByte(SourceLine, TabStop, m_columnToByte);
260*67e74705SXin Li
261*67e74705SXin Li assert(m_byteToColumn.size()==SourceLine.size()+1);
262*67e74705SXin Li assert(0 < m_byteToColumn.size() && 0 < m_columnToByte.size());
263*67e74705SXin Li assert(m_byteToColumn.size()
264*67e74705SXin Li == static_cast<unsigned>(m_columnToByte.back()+1));
265*67e74705SXin Li assert(static_cast<unsigned>(m_byteToColumn.back()+1)
266*67e74705SXin Li == m_columnToByte.size());
267*67e74705SXin Li }
columns__anon3e7c482b0111::SourceColumnMap268*67e74705SXin Li int columns() const { return m_byteToColumn.back(); }
bytes__anon3e7c482b0111::SourceColumnMap269*67e74705SXin Li int bytes() const { return m_columnToByte.back(); }
270*67e74705SXin Li
271*67e74705SXin Li /// \brief Map a byte to the column which it is at the start of, or return -1
272*67e74705SXin Li /// if it is not at the start of a column (for a UTF-8 trailing byte).
byteToColumn__anon3e7c482b0111::SourceColumnMap273*67e74705SXin Li int byteToColumn(int n) const {
274*67e74705SXin Li assert(0<=n && n<static_cast<int>(m_byteToColumn.size()));
275*67e74705SXin Li return m_byteToColumn[n];
276*67e74705SXin Li }
277*67e74705SXin Li
278*67e74705SXin Li /// \brief Map a byte to the first column which contains it.
byteToContainingColumn__anon3e7c482b0111::SourceColumnMap279*67e74705SXin Li int byteToContainingColumn(int N) const {
280*67e74705SXin Li assert(0 <= N && N < static_cast<int>(m_byteToColumn.size()));
281*67e74705SXin Li while (m_byteToColumn[N] == -1)
282*67e74705SXin Li --N;
283*67e74705SXin Li return m_byteToColumn[N];
284*67e74705SXin Li }
285*67e74705SXin Li
286*67e74705SXin Li /// \brief Map a column to the byte which starts the column, or return -1 if
287*67e74705SXin Li /// the column the second or subsequent column of an expanded tab or similar
288*67e74705SXin Li /// multi-column entity.
columnToByte__anon3e7c482b0111::SourceColumnMap289*67e74705SXin Li int columnToByte(int n) const {
290*67e74705SXin Li assert(0<=n && n<static_cast<int>(m_columnToByte.size()));
291*67e74705SXin Li return m_columnToByte[n];
292*67e74705SXin Li }
293*67e74705SXin Li
294*67e74705SXin Li /// \brief Map from a byte index to the next byte which starts a column.
startOfNextColumn__anon3e7c482b0111::SourceColumnMap295*67e74705SXin Li int startOfNextColumn(int N) const {
296*67e74705SXin Li assert(0 <= N && N < static_cast<int>(m_byteToColumn.size() - 1));
297*67e74705SXin Li while (byteToColumn(++N) == -1) {}
298*67e74705SXin Li return N;
299*67e74705SXin Li }
300*67e74705SXin Li
301*67e74705SXin Li /// \brief Map from a byte index to the previous byte which starts a column.
startOfPreviousColumn__anon3e7c482b0111::SourceColumnMap302*67e74705SXin Li int startOfPreviousColumn(int N) const {
303*67e74705SXin Li assert(0 < N && N < static_cast<int>(m_byteToColumn.size()));
304*67e74705SXin Li while (byteToColumn(--N) == -1) {}
305*67e74705SXin Li return N;
306*67e74705SXin Li }
307*67e74705SXin Li
getSourceLine__anon3e7c482b0111::SourceColumnMap308*67e74705SXin Li StringRef getSourceLine() const {
309*67e74705SXin Li return m_SourceLine;
310*67e74705SXin Li }
311*67e74705SXin Li
312*67e74705SXin Li private:
313*67e74705SXin Li const std::string m_SourceLine;
314*67e74705SXin Li SmallVector<int,200> m_byteToColumn;
315*67e74705SXin Li SmallVector<int,200> m_columnToByte;
316*67e74705SXin Li };
317*67e74705SXin Li } // end anonymous namespace
318*67e74705SXin Li
319*67e74705SXin Li /// \brief When the source code line we want to print is too long for
320*67e74705SXin Li /// the terminal, select the "interesting" region.
selectInterestingSourceRegion(std::string & SourceLine,std::string & CaretLine,std::string & FixItInsertionLine,unsigned Columns,const SourceColumnMap & map)321*67e74705SXin Li static void selectInterestingSourceRegion(std::string &SourceLine,
322*67e74705SXin Li std::string &CaretLine,
323*67e74705SXin Li std::string &FixItInsertionLine,
324*67e74705SXin Li unsigned Columns,
325*67e74705SXin Li const SourceColumnMap &map) {
326*67e74705SXin Li unsigned CaretColumns = CaretLine.size();
327*67e74705SXin Li unsigned FixItColumns = llvm::sys::locale::columnWidth(FixItInsertionLine);
328*67e74705SXin Li unsigned MaxColumns = std::max(static_cast<unsigned>(map.columns()),
329*67e74705SXin Li std::max(CaretColumns, FixItColumns));
330*67e74705SXin Li // if the number of columns is less than the desired number we're done
331*67e74705SXin Li if (MaxColumns <= Columns)
332*67e74705SXin Li return;
333*67e74705SXin Li
334*67e74705SXin Li // No special characters are allowed in CaretLine.
335*67e74705SXin Li assert(CaretLine.end() ==
336*67e74705SXin Li std::find_if(CaretLine.begin(), CaretLine.end(),
337*67e74705SXin Li [](char c) { return c < ' ' || '~' < c; }));
338*67e74705SXin Li
339*67e74705SXin Li // Find the slice that we need to display the full caret line
340*67e74705SXin Li // correctly.
341*67e74705SXin Li unsigned CaretStart = 0, CaretEnd = CaretLine.size();
342*67e74705SXin Li for (; CaretStart != CaretEnd; ++CaretStart)
343*67e74705SXin Li if (!isWhitespace(CaretLine[CaretStart]))
344*67e74705SXin Li break;
345*67e74705SXin Li
346*67e74705SXin Li for (; CaretEnd != CaretStart; --CaretEnd)
347*67e74705SXin Li if (!isWhitespace(CaretLine[CaretEnd - 1]))
348*67e74705SXin Li break;
349*67e74705SXin Li
350*67e74705SXin Li // caret has already been inserted into CaretLine so the above whitespace
351*67e74705SXin Li // check is guaranteed to include the caret
352*67e74705SXin Li
353*67e74705SXin Li // If we have a fix-it line, make sure the slice includes all of the
354*67e74705SXin Li // fix-it information.
355*67e74705SXin Li if (!FixItInsertionLine.empty()) {
356*67e74705SXin Li unsigned FixItStart = 0, FixItEnd = FixItInsertionLine.size();
357*67e74705SXin Li for (; FixItStart != FixItEnd; ++FixItStart)
358*67e74705SXin Li if (!isWhitespace(FixItInsertionLine[FixItStart]))
359*67e74705SXin Li break;
360*67e74705SXin Li
361*67e74705SXin Li for (; FixItEnd != FixItStart; --FixItEnd)
362*67e74705SXin Li if (!isWhitespace(FixItInsertionLine[FixItEnd - 1]))
363*67e74705SXin Li break;
364*67e74705SXin Li
365*67e74705SXin Li // We can safely use the byte offset FixItStart as the column offset
366*67e74705SXin Li // because the characters up until FixItStart are all ASCII whitespace
367*67e74705SXin Li // characters.
368*67e74705SXin Li unsigned FixItStartCol = FixItStart;
369*67e74705SXin Li unsigned FixItEndCol
370*67e74705SXin Li = llvm::sys::locale::columnWidth(FixItInsertionLine.substr(0, FixItEnd));
371*67e74705SXin Li
372*67e74705SXin Li CaretStart = std::min(FixItStartCol, CaretStart);
373*67e74705SXin Li CaretEnd = std::max(FixItEndCol, CaretEnd);
374*67e74705SXin Li }
375*67e74705SXin Li
376*67e74705SXin Li // CaretEnd may have been set at the middle of a character
377*67e74705SXin Li // If it's not at a character's first column then advance it past the current
378*67e74705SXin Li // character.
379*67e74705SXin Li while (static_cast<int>(CaretEnd) < map.columns() &&
380*67e74705SXin Li -1 == map.columnToByte(CaretEnd))
381*67e74705SXin Li ++CaretEnd;
382*67e74705SXin Li
383*67e74705SXin Li assert((static_cast<int>(CaretStart) > map.columns() ||
384*67e74705SXin Li -1!=map.columnToByte(CaretStart)) &&
385*67e74705SXin Li "CaretStart must not point to a column in the middle of a source"
386*67e74705SXin Li " line character");
387*67e74705SXin Li assert((static_cast<int>(CaretEnd) > map.columns() ||
388*67e74705SXin Li -1!=map.columnToByte(CaretEnd)) &&
389*67e74705SXin Li "CaretEnd must not point to a column in the middle of a source line"
390*67e74705SXin Li " character");
391*67e74705SXin Li
392*67e74705SXin Li // CaretLine[CaretStart, CaretEnd) contains all of the interesting
393*67e74705SXin Li // parts of the caret line. While this slice is smaller than the
394*67e74705SXin Li // number of columns we have, try to grow the slice to encompass
395*67e74705SXin Li // more context.
396*67e74705SXin Li
397*67e74705SXin Li unsigned SourceStart = map.columnToByte(std::min<unsigned>(CaretStart,
398*67e74705SXin Li map.columns()));
399*67e74705SXin Li unsigned SourceEnd = map.columnToByte(std::min<unsigned>(CaretEnd,
400*67e74705SXin Li map.columns()));
401*67e74705SXin Li
402*67e74705SXin Li unsigned CaretColumnsOutsideSource = CaretEnd-CaretStart
403*67e74705SXin Li - (map.byteToColumn(SourceEnd)-map.byteToColumn(SourceStart));
404*67e74705SXin Li
405*67e74705SXin Li char const *front_ellipse = " ...";
406*67e74705SXin Li char const *front_space = " ";
407*67e74705SXin Li char const *back_ellipse = "...";
408*67e74705SXin Li unsigned ellipses_space = strlen(front_ellipse) + strlen(back_ellipse);
409*67e74705SXin Li
410*67e74705SXin Li unsigned TargetColumns = Columns;
411*67e74705SXin Li // Give us extra room for the ellipses
412*67e74705SXin Li // and any of the caret line that extends past the source
413*67e74705SXin Li if (TargetColumns > ellipses_space+CaretColumnsOutsideSource)
414*67e74705SXin Li TargetColumns -= ellipses_space+CaretColumnsOutsideSource;
415*67e74705SXin Li
416*67e74705SXin Li while (SourceStart>0 || SourceEnd<SourceLine.size()) {
417*67e74705SXin Li bool ExpandedRegion = false;
418*67e74705SXin Li
419*67e74705SXin Li if (SourceStart>0) {
420*67e74705SXin Li unsigned NewStart = map.startOfPreviousColumn(SourceStart);
421*67e74705SXin Li
422*67e74705SXin Li // Skip over any whitespace we see here; we're looking for
423*67e74705SXin Li // another bit of interesting text.
424*67e74705SXin Li // FIXME: Detect non-ASCII whitespace characters too.
425*67e74705SXin Li while (NewStart && isWhitespace(SourceLine[NewStart]))
426*67e74705SXin Li NewStart = map.startOfPreviousColumn(NewStart);
427*67e74705SXin Li
428*67e74705SXin Li // Skip over this bit of "interesting" text.
429*67e74705SXin Li while (NewStart) {
430*67e74705SXin Li unsigned Prev = map.startOfPreviousColumn(NewStart);
431*67e74705SXin Li if (isWhitespace(SourceLine[Prev]))
432*67e74705SXin Li break;
433*67e74705SXin Li NewStart = Prev;
434*67e74705SXin Li }
435*67e74705SXin Li
436*67e74705SXin Li assert(map.byteToColumn(NewStart) != -1);
437*67e74705SXin Li unsigned NewColumns = map.byteToColumn(SourceEnd) -
438*67e74705SXin Li map.byteToColumn(NewStart);
439*67e74705SXin Li if (NewColumns <= TargetColumns) {
440*67e74705SXin Li SourceStart = NewStart;
441*67e74705SXin Li ExpandedRegion = true;
442*67e74705SXin Li }
443*67e74705SXin Li }
444*67e74705SXin Li
445*67e74705SXin Li if (SourceEnd<SourceLine.size()) {
446*67e74705SXin Li unsigned NewEnd = map.startOfNextColumn(SourceEnd);
447*67e74705SXin Li
448*67e74705SXin Li // Skip over any whitespace we see here; we're looking for
449*67e74705SXin Li // another bit of interesting text.
450*67e74705SXin Li // FIXME: Detect non-ASCII whitespace characters too.
451*67e74705SXin Li while (NewEnd < SourceLine.size() && isWhitespace(SourceLine[NewEnd]))
452*67e74705SXin Li NewEnd = map.startOfNextColumn(NewEnd);
453*67e74705SXin Li
454*67e74705SXin Li // Skip over this bit of "interesting" text.
455*67e74705SXin Li while (NewEnd < SourceLine.size() && isWhitespace(SourceLine[NewEnd]))
456*67e74705SXin Li NewEnd = map.startOfNextColumn(NewEnd);
457*67e74705SXin Li
458*67e74705SXin Li assert(map.byteToColumn(NewEnd) != -1);
459*67e74705SXin Li unsigned NewColumns = map.byteToColumn(NewEnd) -
460*67e74705SXin Li map.byteToColumn(SourceStart);
461*67e74705SXin Li if (NewColumns <= TargetColumns) {
462*67e74705SXin Li SourceEnd = NewEnd;
463*67e74705SXin Li ExpandedRegion = true;
464*67e74705SXin Li }
465*67e74705SXin Li }
466*67e74705SXin Li
467*67e74705SXin Li if (!ExpandedRegion)
468*67e74705SXin Li break;
469*67e74705SXin Li }
470*67e74705SXin Li
471*67e74705SXin Li CaretStart = map.byteToColumn(SourceStart);
472*67e74705SXin Li CaretEnd = map.byteToColumn(SourceEnd) + CaretColumnsOutsideSource;
473*67e74705SXin Li
474*67e74705SXin Li // [CaretStart, CaretEnd) is the slice we want. Update the various
475*67e74705SXin Li // output lines to show only this slice, with two-space padding
476*67e74705SXin Li // before the lines so that it looks nicer.
477*67e74705SXin Li
478*67e74705SXin Li assert(CaretStart!=(unsigned)-1 && CaretEnd!=(unsigned)-1 &&
479*67e74705SXin Li SourceStart!=(unsigned)-1 && SourceEnd!=(unsigned)-1);
480*67e74705SXin Li assert(SourceStart <= SourceEnd);
481*67e74705SXin Li assert(CaretStart <= CaretEnd);
482*67e74705SXin Li
483*67e74705SXin Li unsigned BackColumnsRemoved
484*67e74705SXin Li = map.byteToColumn(SourceLine.size())-map.byteToColumn(SourceEnd);
485*67e74705SXin Li unsigned FrontColumnsRemoved = CaretStart;
486*67e74705SXin Li unsigned ColumnsKept = CaretEnd-CaretStart;
487*67e74705SXin Li
488*67e74705SXin Li // We checked up front that the line needed truncation
489*67e74705SXin Li assert(FrontColumnsRemoved+ColumnsKept+BackColumnsRemoved > Columns);
490*67e74705SXin Li
491*67e74705SXin Li // The line needs some truncation, and we'd prefer to keep the front
492*67e74705SXin Li // if possible, so remove the back
493*67e74705SXin Li if (BackColumnsRemoved > strlen(back_ellipse))
494*67e74705SXin Li SourceLine.replace(SourceEnd, std::string::npos, back_ellipse);
495*67e74705SXin Li
496*67e74705SXin Li // If that's enough then we're done
497*67e74705SXin Li if (FrontColumnsRemoved+ColumnsKept <= Columns)
498*67e74705SXin Li return;
499*67e74705SXin Li
500*67e74705SXin Li // Otherwise remove the front as well
501*67e74705SXin Li if (FrontColumnsRemoved > strlen(front_ellipse)) {
502*67e74705SXin Li SourceLine.replace(0, SourceStart, front_ellipse);
503*67e74705SXin Li CaretLine.replace(0, CaretStart, front_space);
504*67e74705SXin Li if (!FixItInsertionLine.empty())
505*67e74705SXin Li FixItInsertionLine.replace(0, CaretStart, front_space);
506*67e74705SXin Li }
507*67e74705SXin Li }
508*67e74705SXin Li
509*67e74705SXin Li /// \brief Skip over whitespace in the string, starting at the given
510*67e74705SXin Li /// index.
511*67e74705SXin Li ///
512*67e74705SXin Li /// \returns The index of the first non-whitespace character that is
513*67e74705SXin Li /// greater than or equal to Idx or, if no such character exists,
514*67e74705SXin Li /// returns the end of the string.
skipWhitespace(unsigned Idx,StringRef Str,unsigned Length)515*67e74705SXin Li static unsigned skipWhitespace(unsigned Idx, StringRef Str, unsigned Length) {
516*67e74705SXin Li while (Idx < Length && isWhitespace(Str[Idx]))
517*67e74705SXin Li ++Idx;
518*67e74705SXin Li return Idx;
519*67e74705SXin Li }
520*67e74705SXin Li
521*67e74705SXin Li /// \brief If the given character is the start of some kind of
522*67e74705SXin Li /// balanced punctuation (e.g., quotes or parentheses), return the
523*67e74705SXin Li /// character that will terminate the punctuation.
524*67e74705SXin Li ///
525*67e74705SXin Li /// \returns The ending punctuation character, if any, or the NULL
526*67e74705SXin Li /// character if the input character does not start any punctuation.
findMatchingPunctuation(char c)527*67e74705SXin Li static inline char findMatchingPunctuation(char c) {
528*67e74705SXin Li switch (c) {
529*67e74705SXin Li case '\'': return '\'';
530*67e74705SXin Li case '`': return '\'';
531*67e74705SXin Li case '"': return '"';
532*67e74705SXin Li case '(': return ')';
533*67e74705SXin Li case '[': return ']';
534*67e74705SXin Li case '{': return '}';
535*67e74705SXin Li default: break;
536*67e74705SXin Li }
537*67e74705SXin Li
538*67e74705SXin Li return 0;
539*67e74705SXin Li }
540*67e74705SXin Li
541*67e74705SXin Li /// \brief Find the end of the word starting at the given offset
542*67e74705SXin Li /// within a string.
543*67e74705SXin Li ///
544*67e74705SXin Li /// \returns the index pointing one character past the end of the
545*67e74705SXin Li /// word.
findEndOfWord(unsigned Start,StringRef Str,unsigned Length,unsigned Column,unsigned Columns)546*67e74705SXin Li static unsigned findEndOfWord(unsigned Start, StringRef Str,
547*67e74705SXin Li unsigned Length, unsigned Column,
548*67e74705SXin Li unsigned Columns) {
549*67e74705SXin Li assert(Start < Str.size() && "Invalid start position!");
550*67e74705SXin Li unsigned End = Start + 1;
551*67e74705SXin Li
552*67e74705SXin Li // If we are already at the end of the string, take that as the word.
553*67e74705SXin Li if (End == Str.size())
554*67e74705SXin Li return End;
555*67e74705SXin Li
556*67e74705SXin Li // Determine if the start of the string is actually opening
557*67e74705SXin Li // punctuation, e.g., a quote or parentheses.
558*67e74705SXin Li char EndPunct = findMatchingPunctuation(Str[Start]);
559*67e74705SXin Li if (!EndPunct) {
560*67e74705SXin Li // This is a normal word. Just find the first space character.
561*67e74705SXin Li while (End < Length && !isWhitespace(Str[End]))
562*67e74705SXin Li ++End;
563*67e74705SXin Li return End;
564*67e74705SXin Li }
565*67e74705SXin Li
566*67e74705SXin Li // We have the start of a balanced punctuation sequence (quotes,
567*67e74705SXin Li // parentheses, etc.). Determine the full sequence is.
568*67e74705SXin Li SmallString<16> PunctuationEndStack;
569*67e74705SXin Li PunctuationEndStack.push_back(EndPunct);
570*67e74705SXin Li while (End < Length && !PunctuationEndStack.empty()) {
571*67e74705SXin Li if (Str[End] == PunctuationEndStack.back())
572*67e74705SXin Li PunctuationEndStack.pop_back();
573*67e74705SXin Li else if (char SubEndPunct = findMatchingPunctuation(Str[End]))
574*67e74705SXin Li PunctuationEndStack.push_back(SubEndPunct);
575*67e74705SXin Li
576*67e74705SXin Li ++End;
577*67e74705SXin Li }
578*67e74705SXin Li
579*67e74705SXin Li // Find the first space character after the punctuation ended.
580*67e74705SXin Li while (End < Length && !isWhitespace(Str[End]))
581*67e74705SXin Li ++End;
582*67e74705SXin Li
583*67e74705SXin Li unsigned PunctWordLength = End - Start;
584*67e74705SXin Li if (// If the word fits on this line
585*67e74705SXin Li Column + PunctWordLength <= Columns ||
586*67e74705SXin Li // ... or the word is "short enough" to take up the next line
587*67e74705SXin Li // without too much ugly white space
588*67e74705SXin Li PunctWordLength < Columns/3)
589*67e74705SXin Li return End; // Take the whole thing as a single "word".
590*67e74705SXin Li
591*67e74705SXin Li // The whole quoted/parenthesized string is too long to print as a
592*67e74705SXin Li // single "word". Instead, find the "word" that starts just after
593*67e74705SXin Li // the punctuation and use that end-point instead. This will recurse
594*67e74705SXin Li // until it finds something small enough to consider a word.
595*67e74705SXin Li return findEndOfWord(Start + 1, Str, Length, Column + 1, Columns);
596*67e74705SXin Li }
597*67e74705SXin Li
598*67e74705SXin Li /// \brief Print the given string to a stream, word-wrapping it to
599*67e74705SXin Li /// some number of columns in the process.
600*67e74705SXin Li ///
601*67e74705SXin Li /// \param OS the stream to which the word-wrapping string will be
602*67e74705SXin Li /// emitted.
603*67e74705SXin Li /// \param Str the string to word-wrap and output.
604*67e74705SXin Li /// \param Columns the number of columns to word-wrap to.
605*67e74705SXin Li /// \param Column the column number at which the first character of \p
606*67e74705SXin Li /// Str will be printed. This will be non-zero when part of the first
607*67e74705SXin Li /// line has already been printed.
608*67e74705SXin Li /// \param Bold if the current text should be bold
609*67e74705SXin Li /// \param Indentation the number of spaces to indent any lines beyond
610*67e74705SXin Li /// the first line.
611*67e74705SXin Li /// \returns true if word-wrapping was required, or false if the
612*67e74705SXin Li /// string fit on the first line.
printWordWrapped(raw_ostream & OS,StringRef Str,unsigned Columns,unsigned Column=0,bool Bold=false,unsigned Indentation=WordWrapIndentation)613*67e74705SXin Li static bool printWordWrapped(raw_ostream &OS, StringRef Str,
614*67e74705SXin Li unsigned Columns,
615*67e74705SXin Li unsigned Column = 0,
616*67e74705SXin Li bool Bold = false,
617*67e74705SXin Li unsigned Indentation = WordWrapIndentation) {
618*67e74705SXin Li const unsigned Length = std::min(Str.find('\n'), Str.size());
619*67e74705SXin Li bool TextNormal = true;
620*67e74705SXin Li
621*67e74705SXin Li // The string used to indent each line.
622*67e74705SXin Li SmallString<16> IndentStr;
623*67e74705SXin Li IndentStr.assign(Indentation, ' ');
624*67e74705SXin Li bool Wrapped = false;
625*67e74705SXin Li for (unsigned WordStart = 0, WordEnd; WordStart < Length;
626*67e74705SXin Li WordStart = WordEnd) {
627*67e74705SXin Li // Find the beginning of the next word.
628*67e74705SXin Li WordStart = skipWhitespace(WordStart, Str, Length);
629*67e74705SXin Li if (WordStart == Length)
630*67e74705SXin Li break;
631*67e74705SXin Li
632*67e74705SXin Li // Find the end of this word.
633*67e74705SXin Li WordEnd = findEndOfWord(WordStart, Str, Length, Column, Columns);
634*67e74705SXin Li
635*67e74705SXin Li // Does this word fit on the current line?
636*67e74705SXin Li unsigned WordLength = WordEnd - WordStart;
637*67e74705SXin Li if (Column + WordLength < Columns) {
638*67e74705SXin Li // This word fits on the current line; print it there.
639*67e74705SXin Li if (WordStart) {
640*67e74705SXin Li OS << ' ';
641*67e74705SXin Li Column += 1;
642*67e74705SXin Li }
643*67e74705SXin Li applyTemplateHighlighting(OS, Str.substr(WordStart, WordLength),
644*67e74705SXin Li TextNormal, Bold);
645*67e74705SXin Li Column += WordLength;
646*67e74705SXin Li continue;
647*67e74705SXin Li }
648*67e74705SXin Li
649*67e74705SXin Li // This word does not fit on the current line, so wrap to the next
650*67e74705SXin Li // line.
651*67e74705SXin Li OS << '\n';
652*67e74705SXin Li OS.write(&IndentStr[0], Indentation);
653*67e74705SXin Li applyTemplateHighlighting(OS, Str.substr(WordStart, WordLength),
654*67e74705SXin Li TextNormal, Bold);
655*67e74705SXin Li Column = Indentation + WordLength;
656*67e74705SXin Li Wrapped = true;
657*67e74705SXin Li }
658*67e74705SXin Li
659*67e74705SXin Li // Append any remaning text from the message with its existing formatting.
660*67e74705SXin Li applyTemplateHighlighting(OS, Str.substr(Length), TextNormal, Bold);
661*67e74705SXin Li
662*67e74705SXin Li assert(TextNormal && "Text highlighted at end of diagnostic message.");
663*67e74705SXin Li
664*67e74705SXin Li return Wrapped;
665*67e74705SXin Li }
666*67e74705SXin Li
TextDiagnostic(raw_ostream & OS,const LangOptions & LangOpts,DiagnosticOptions * DiagOpts)667*67e74705SXin Li TextDiagnostic::TextDiagnostic(raw_ostream &OS,
668*67e74705SXin Li const LangOptions &LangOpts,
669*67e74705SXin Li DiagnosticOptions *DiagOpts)
670*67e74705SXin Li : DiagnosticRenderer(LangOpts, DiagOpts), OS(OS) {}
671*67e74705SXin Li
~TextDiagnostic()672*67e74705SXin Li TextDiagnostic::~TextDiagnostic() {}
673*67e74705SXin Li
674*67e74705SXin Li void
emitDiagnosticMessage(SourceLocation Loc,PresumedLoc PLoc,DiagnosticsEngine::Level Level,StringRef Message,ArrayRef<clang::CharSourceRange> Ranges,const SourceManager * SM,DiagOrStoredDiag D)675*67e74705SXin Li TextDiagnostic::emitDiagnosticMessage(SourceLocation Loc,
676*67e74705SXin Li PresumedLoc PLoc,
677*67e74705SXin Li DiagnosticsEngine::Level Level,
678*67e74705SXin Li StringRef Message,
679*67e74705SXin Li ArrayRef<clang::CharSourceRange> Ranges,
680*67e74705SXin Li const SourceManager *SM,
681*67e74705SXin Li DiagOrStoredDiag D) {
682*67e74705SXin Li uint64_t StartOfLocationInfo = OS.tell();
683*67e74705SXin Li
684*67e74705SXin Li // Emit the location of this particular diagnostic.
685*67e74705SXin Li if (Loc.isValid())
686*67e74705SXin Li emitDiagnosticLoc(Loc, PLoc, Level, Ranges, *SM);
687*67e74705SXin Li
688*67e74705SXin Li if (DiagOpts->ShowColors)
689*67e74705SXin Li OS.resetColor();
690*67e74705SXin Li
691*67e74705SXin Li printDiagnosticLevel(OS, Level, DiagOpts->ShowColors,
692*67e74705SXin Li DiagOpts->CLFallbackMode);
693*67e74705SXin Li printDiagnosticMessage(OS,
694*67e74705SXin Li /*IsSupplemental*/ Level == DiagnosticsEngine::Note,
695*67e74705SXin Li Message, OS.tell() - StartOfLocationInfo,
696*67e74705SXin Li DiagOpts->MessageLength, DiagOpts->ShowColors);
697*67e74705SXin Li }
698*67e74705SXin Li
699*67e74705SXin Li /*static*/ void
printDiagnosticLevel(raw_ostream & OS,DiagnosticsEngine::Level Level,bool ShowColors,bool CLFallbackMode)700*67e74705SXin Li TextDiagnostic::printDiagnosticLevel(raw_ostream &OS,
701*67e74705SXin Li DiagnosticsEngine::Level Level,
702*67e74705SXin Li bool ShowColors,
703*67e74705SXin Li bool CLFallbackMode) {
704*67e74705SXin Li if (ShowColors) {
705*67e74705SXin Li // Print diagnostic category in bold and color
706*67e74705SXin Li switch (Level) {
707*67e74705SXin Li case DiagnosticsEngine::Ignored:
708*67e74705SXin Li llvm_unreachable("Invalid diagnostic type");
709*67e74705SXin Li case DiagnosticsEngine::Note: OS.changeColor(noteColor, true); break;
710*67e74705SXin Li case DiagnosticsEngine::Remark: OS.changeColor(remarkColor, true); break;
711*67e74705SXin Li case DiagnosticsEngine::Warning: OS.changeColor(warningColor, true); break;
712*67e74705SXin Li case DiagnosticsEngine::Error: OS.changeColor(errorColor, true); break;
713*67e74705SXin Li case DiagnosticsEngine::Fatal: OS.changeColor(fatalColor, true); break;
714*67e74705SXin Li }
715*67e74705SXin Li }
716*67e74705SXin Li
717*67e74705SXin Li switch (Level) {
718*67e74705SXin Li case DiagnosticsEngine::Ignored:
719*67e74705SXin Li llvm_unreachable("Invalid diagnostic type");
720*67e74705SXin Li case DiagnosticsEngine::Note: OS << "note"; break;
721*67e74705SXin Li case DiagnosticsEngine::Remark: OS << "remark"; break;
722*67e74705SXin Li case DiagnosticsEngine::Warning: OS << "warning"; break;
723*67e74705SXin Li case DiagnosticsEngine::Error: OS << "error"; break;
724*67e74705SXin Li case DiagnosticsEngine::Fatal: OS << "fatal error"; break;
725*67e74705SXin Li }
726*67e74705SXin Li
727*67e74705SXin Li // In clang-cl /fallback mode, print diagnostics as "error(clang):". This
728*67e74705SXin Li // makes it more clear whether a message is coming from clang or cl.exe,
729*67e74705SXin Li // and it prevents MSBuild from concluding that the build failed just because
730*67e74705SXin Li // there is an "error:" in the output.
731*67e74705SXin Li if (CLFallbackMode)
732*67e74705SXin Li OS << "(clang)";
733*67e74705SXin Li
734*67e74705SXin Li OS << ": ";
735*67e74705SXin Li
736*67e74705SXin Li if (ShowColors)
737*67e74705SXin Li OS.resetColor();
738*67e74705SXin Li }
739*67e74705SXin Li
740*67e74705SXin Li /*static*/
printDiagnosticMessage(raw_ostream & OS,bool IsSupplemental,StringRef Message,unsigned CurrentColumn,unsigned Columns,bool ShowColors)741*67e74705SXin Li void TextDiagnostic::printDiagnosticMessage(raw_ostream &OS,
742*67e74705SXin Li bool IsSupplemental,
743*67e74705SXin Li StringRef Message,
744*67e74705SXin Li unsigned CurrentColumn,
745*67e74705SXin Li unsigned Columns, bool ShowColors) {
746*67e74705SXin Li bool Bold = false;
747*67e74705SXin Li if (ShowColors && !IsSupplemental) {
748*67e74705SXin Li // Print primary diagnostic messages in bold and without color, to visually
749*67e74705SXin Li // indicate the transition from continuation notes and other output.
750*67e74705SXin Li OS.changeColor(savedColor, true);
751*67e74705SXin Li Bold = true;
752*67e74705SXin Li }
753*67e74705SXin Li
754*67e74705SXin Li if (Columns)
755*67e74705SXin Li printWordWrapped(OS, Message, Columns, CurrentColumn, Bold);
756*67e74705SXin Li else {
757*67e74705SXin Li bool Normal = true;
758*67e74705SXin Li applyTemplateHighlighting(OS, Message, Normal, Bold);
759*67e74705SXin Li assert(Normal && "Formatting should have returned to normal");
760*67e74705SXin Li }
761*67e74705SXin Li
762*67e74705SXin Li if (ShowColors)
763*67e74705SXin Li OS.resetColor();
764*67e74705SXin Li OS << '\n';
765*67e74705SXin Li }
766*67e74705SXin Li
767*67e74705SXin Li /// \brief Print out the file/line/column information and include trace.
768*67e74705SXin Li ///
769*67e74705SXin Li /// This method handlen the emission of the diagnostic location information.
770*67e74705SXin Li /// This includes extracting as much location information as is present for
771*67e74705SXin Li /// the diagnostic and printing it, as well as any include stack or source
772*67e74705SXin Li /// ranges necessary.
emitDiagnosticLoc(SourceLocation Loc,PresumedLoc PLoc,DiagnosticsEngine::Level Level,ArrayRef<CharSourceRange> Ranges,const SourceManager & SM)773*67e74705SXin Li void TextDiagnostic::emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
774*67e74705SXin Li DiagnosticsEngine::Level Level,
775*67e74705SXin Li ArrayRef<CharSourceRange> Ranges,
776*67e74705SXin Li const SourceManager &SM) {
777*67e74705SXin Li if (PLoc.isInvalid()) {
778*67e74705SXin Li // At least print the file name if available:
779*67e74705SXin Li FileID FID = SM.getFileID(Loc);
780*67e74705SXin Li if (FID.isValid()) {
781*67e74705SXin Li const FileEntry* FE = SM.getFileEntryForID(FID);
782*67e74705SXin Li if (FE && FE->isValid()) {
783*67e74705SXin Li OS << FE->getName();
784*67e74705SXin Li if (FE->isInPCH())
785*67e74705SXin Li OS << " (in PCH)";
786*67e74705SXin Li OS << ": ";
787*67e74705SXin Li }
788*67e74705SXin Li }
789*67e74705SXin Li return;
790*67e74705SXin Li }
791*67e74705SXin Li unsigned LineNo = PLoc.getLine();
792*67e74705SXin Li
793*67e74705SXin Li if (!DiagOpts->ShowLocation)
794*67e74705SXin Li return;
795*67e74705SXin Li
796*67e74705SXin Li if (DiagOpts->ShowColors)
797*67e74705SXin Li OS.changeColor(savedColor, true);
798*67e74705SXin Li
799*67e74705SXin Li OS << PLoc.getFilename();
800*67e74705SXin Li switch (DiagOpts->getFormat()) {
801*67e74705SXin Li case DiagnosticOptions::Clang: OS << ':' << LineNo; break;
802*67e74705SXin Li case DiagnosticOptions::MSVC: OS << '(' << LineNo; break;
803*67e74705SXin Li case DiagnosticOptions::Vi: OS << " +" << LineNo; break;
804*67e74705SXin Li }
805*67e74705SXin Li
806*67e74705SXin Li if (DiagOpts->ShowColumn)
807*67e74705SXin Li // Compute the column number.
808*67e74705SXin Li if (unsigned ColNo = PLoc.getColumn()) {
809*67e74705SXin Li if (DiagOpts->getFormat() == DiagnosticOptions::MSVC) {
810*67e74705SXin Li OS << ',';
811*67e74705SXin Li // Visual Studio 2010 or earlier expects column number to be off by one
812*67e74705SXin Li if (LangOpts.MSCompatibilityVersion &&
813*67e74705SXin Li !LangOpts.isCompatibleWithMSVC(LangOptions::MSVC2012))
814*67e74705SXin Li ColNo--;
815*67e74705SXin Li } else
816*67e74705SXin Li OS << ':';
817*67e74705SXin Li OS << ColNo;
818*67e74705SXin Li }
819*67e74705SXin Li switch (DiagOpts->getFormat()) {
820*67e74705SXin Li case DiagnosticOptions::Clang:
821*67e74705SXin Li case DiagnosticOptions::Vi: OS << ':'; break;
822*67e74705SXin Li case DiagnosticOptions::MSVC:
823*67e74705SXin Li // MSVC2013 and before print 'file(4) : error'. MSVC2015 gets rid of the
824*67e74705SXin Li // space and prints 'file(4): error'.
825*67e74705SXin Li OS << ')';
826*67e74705SXin Li if (LangOpts.MSCompatibilityVersion &&
827*67e74705SXin Li !LangOpts.isCompatibleWithMSVC(LangOptions::MSVC2015))
828*67e74705SXin Li OS << ' ';
829*67e74705SXin Li OS << ": ";
830*67e74705SXin Li break;
831*67e74705SXin Li }
832*67e74705SXin Li
833*67e74705SXin Li if (DiagOpts->ShowSourceRanges && !Ranges.empty()) {
834*67e74705SXin Li FileID CaretFileID =
835*67e74705SXin Li SM.getFileID(SM.getExpansionLoc(Loc));
836*67e74705SXin Li bool PrintedRange = false;
837*67e74705SXin Li
838*67e74705SXin Li for (ArrayRef<CharSourceRange>::const_iterator RI = Ranges.begin(),
839*67e74705SXin Li RE = Ranges.end();
840*67e74705SXin Li RI != RE; ++RI) {
841*67e74705SXin Li // Ignore invalid ranges.
842*67e74705SXin Li if (!RI->isValid()) continue;
843*67e74705SXin Li
844*67e74705SXin Li SourceLocation B = SM.getExpansionLoc(RI->getBegin());
845*67e74705SXin Li SourceLocation E = SM.getExpansionLoc(RI->getEnd());
846*67e74705SXin Li
847*67e74705SXin Li // If the End location and the start location are the same and are a
848*67e74705SXin Li // macro location, then the range was something that came from a
849*67e74705SXin Li // macro expansion or _Pragma. If this is an object-like macro, the
850*67e74705SXin Li // best we can do is to highlight the range. If this is a
851*67e74705SXin Li // function-like macro, we'd also like to highlight the arguments.
852*67e74705SXin Li if (B == E && RI->getEnd().isMacroID())
853*67e74705SXin Li E = SM.getExpansionRange(RI->getEnd()).second;
854*67e74705SXin Li
855*67e74705SXin Li std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(B);
856*67e74705SXin Li std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(E);
857*67e74705SXin Li
858*67e74705SXin Li // If the start or end of the range is in another file, just discard
859*67e74705SXin Li // it.
860*67e74705SXin Li if (BInfo.first != CaretFileID || EInfo.first != CaretFileID)
861*67e74705SXin Li continue;
862*67e74705SXin Li
863*67e74705SXin Li // Add in the length of the token, so that we cover multi-char
864*67e74705SXin Li // tokens.
865*67e74705SXin Li unsigned TokSize = 0;
866*67e74705SXin Li if (RI->isTokenRange())
867*67e74705SXin Li TokSize = Lexer::MeasureTokenLength(E, SM, LangOpts);
868*67e74705SXin Li
869*67e74705SXin Li OS << '{' << SM.getLineNumber(BInfo.first, BInfo.second) << ':'
870*67e74705SXin Li << SM.getColumnNumber(BInfo.first, BInfo.second) << '-'
871*67e74705SXin Li << SM.getLineNumber(EInfo.first, EInfo.second) << ':'
872*67e74705SXin Li << (SM.getColumnNumber(EInfo.first, EInfo.second)+TokSize)
873*67e74705SXin Li << '}';
874*67e74705SXin Li PrintedRange = true;
875*67e74705SXin Li }
876*67e74705SXin Li
877*67e74705SXin Li if (PrintedRange)
878*67e74705SXin Li OS << ':';
879*67e74705SXin Li }
880*67e74705SXin Li OS << ' ';
881*67e74705SXin Li }
882*67e74705SXin Li
emitIncludeLocation(SourceLocation Loc,PresumedLoc PLoc,const SourceManager & SM)883*67e74705SXin Li void TextDiagnostic::emitIncludeLocation(SourceLocation Loc,
884*67e74705SXin Li PresumedLoc PLoc,
885*67e74705SXin Li const SourceManager &SM) {
886*67e74705SXin Li if (DiagOpts->ShowLocation && PLoc.isValid())
887*67e74705SXin Li OS << "In file included from " << PLoc.getFilename() << ':'
888*67e74705SXin Li << PLoc.getLine() << ":\n";
889*67e74705SXin Li else
890*67e74705SXin Li OS << "In included file:\n";
891*67e74705SXin Li }
892*67e74705SXin Li
emitImportLocation(SourceLocation Loc,PresumedLoc PLoc,StringRef ModuleName,const SourceManager & SM)893*67e74705SXin Li void TextDiagnostic::emitImportLocation(SourceLocation Loc, PresumedLoc PLoc,
894*67e74705SXin Li StringRef ModuleName,
895*67e74705SXin Li const SourceManager &SM) {
896*67e74705SXin Li if (DiagOpts->ShowLocation && PLoc.isValid())
897*67e74705SXin Li OS << "In module '" << ModuleName << "' imported from "
898*67e74705SXin Li << PLoc.getFilename() << ':' << PLoc.getLine() << ":\n";
899*67e74705SXin Li else
900*67e74705SXin Li OS << "In module '" << ModuleName << "':\n";
901*67e74705SXin Li }
902*67e74705SXin Li
emitBuildingModuleLocation(SourceLocation Loc,PresumedLoc PLoc,StringRef ModuleName,const SourceManager & SM)903*67e74705SXin Li void TextDiagnostic::emitBuildingModuleLocation(SourceLocation Loc,
904*67e74705SXin Li PresumedLoc PLoc,
905*67e74705SXin Li StringRef ModuleName,
906*67e74705SXin Li const SourceManager &SM) {
907*67e74705SXin Li if (DiagOpts->ShowLocation && PLoc.isValid())
908*67e74705SXin Li OS << "While building module '" << ModuleName << "' imported from "
909*67e74705SXin Li << PLoc.getFilename() << ':' << PLoc.getLine() << ":\n";
910*67e74705SXin Li else
911*67e74705SXin Li OS << "While building module '" << ModuleName << "':\n";
912*67e74705SXin Li }
913*67e74705SXin Li
914*67e74705SXin Li /// \brief Highlight a SourceRange (with ~'s) for any characters on LineNo.
highlightRange(const CharSourceRange & R,unsigned LineNo,FileID FID,const SourceColumnMap & map,std::string & CaretLine,const SourceManager & SM,const LangOptions & LangOpts)915*67e74705SXin Li static void highlightRange(const CharSourceRange &R,
916*67e74705SXin Li unsigned LineNo, FileID FID,
917*67e74705SXin Li const SourceColumnMap &map,
918*67e74705SXin Li std::string &CaretLine,
919*67e74705SXin Li const SourceManager &SM,
920*67e74705SXin Li const LangOptions &LangOpts) {
921*67e74705SXin Li if (!R.isValid()) return;
922*67e74705SXin Li
923*67e74705SXin Li SourceLocation Begin = R.getBegin();
924*67e74705SXin Li SourceLocation End = R.getEnd();
925*67e74705SXin Li
926*67e74705SXin Li unsigned StartLineNo = SM.getExpansionLineNumber(Begin);
927*67e74705SXin Li if (StartLineNo > LineNo || SM.getFileID(Begin) != FID)
928*67e74705SXin Li return; // No intersection.
929*67e74705SXin Li
930*67e74705SXin Li unsigned EndLineNo = SM.getExpansionLineNumber(End);
931*67e74705SXin Li if (EndLineNo < LineNo || SM.getFileID(End) != FID)
932*67e74705SXin Li return; // No intersection.
933*67e74705SXin Li
934*67e74705SXin Li // Compute the column number of the start.
935*67e74705SXin Li unsigned StartColNo = 0;
936*67e74705SXin Li if (StartLineNo == LineNo) {
937*67e74705SXin Li StartColNo = SM.getExpansionColumnNumber(Begin);
938*67e74705SXin Li if (StartColNo) --StartColNo; // Zero base the col #.
939*67e74705SXin Li }
940*67e74705SXin Li
941*67e74705SXin Li // Compute the column number of the end.
942*67e74705SXin Li unsigned EndColNo = map.getSourceLine().size();
943*67e74705SXin Li if (EndLineNo == LineNo) {
944*67e74705SXin Li EndColNo = SM.getExpansionColumnNumber(End);
945*67e74705SXin Li if (EndColNo) {
946*67e74705SXin Li --EndColNo; // Zero base the col #.
947*67e74705SXin Li
948*67e74705SXin Li // Add in the length of the token, so that we cover multi-char tokens if
949*67e74705SXin Li // this is a token range.
950*67e74705SXin Li if (R.isTokenRange())
951*67e74705SXin Li EndColNo += Lexer::MeasureTokenLength(End, SM, LangOpts);
952*67e74705SXin Li } else {
953*67e74705SXin Li EndColNo = CaretLine.size();
954*67e74705SXin Li }
955*67e74705SXin Li }
956*67e74705SXin Li
957*67e74705SXin Li assert(StartColNo <= EndColNo && "Invalid range!");
958*67e74705SXin Li
959*67e74705SXin Li // Check that a token range does not highlight only whitespace.
960*67e74705SXin Li if (R.isTokenRange()) {
961*67e74705SXin Li // Pick the first non-whitespace column.
962*67e74705SXin Li while (StartColNo < map.getSourceLine().size() &&
963*67e74705SXin Li (map.getSourceLine()[StartColNo] == ' ' ||
964*67e74705SXin Li map.getSourceLine()[StartColNo] == '\t'))
965*67e74705SXin Li StartColNo = map.startOfNextColumn(StartColNo);
966*67e74705SXin Li
967*67e74705SXin Li // Pick the last non-whitespace column.
968*67e74705SXin Li if (EndColNo > map.getSourceLine().size())
969*67e74705SXin Li EndColNo = map.getSourceLine().size();
970*67e74705SXin Li while (EndColNo &&
971*67e74705SXin Li (map.getSourceLine()[EndColNo-1] == ' ' ||
972*67e74705SXin Li map.getSourceLine()[EndColNo-1] == '\t'))
973*67e74705SXin Li EndColNo = map.startOfPreviousColumn(EndColNo);
974*67e74705SXin Li
975*67e74705SXin Li // If the start/end passed each other, then we are trying to highlight a
976*67e74705SXin Li // range that just exists in whitespace, which must be some sort of other
977*67e74705SXin Li // bug.
978*67e74705SXin Li assert(StartColNo <= EndColNo && "Trying to highlight whitespace??");
979*67e74705SXin Li }
980*67e74705SXin Li
981*67e74705SXin Li assert(StartColNo <= map.getSourceLine().size() && "Invalid range!");
982*67e74705SXin Li assert(EndColNo <= map.getSourceLine().size() && "Invalid range!");
983*67e74705SXin Li
984*67e74705SXin Li // Fill the range with ~'s.
985*67e74705SXin Li StartColNo = map.byteToContainingColumn(StartColNo);
986*67e74705SXin Li EndColNo = map.byteToContainingColumn(EndColNo);
987*67e74705SXin Li
988*67e74705SXin Li assert(StartColNo <= EndColNo && "Invalid range!");
989*67e74705SXin Li if (CaretLine.size() < EndColNo)
990*67e74705SXin Li CaretLine.resize(EndColNo,' ');
991*67e74705SXin Li std::fill(CaretLine.begin()+StartColNo,CaretLine.begin()+EndColNo,'~');
992*67e74705SXin Li }
993*67e74705SXin Li
buildFixItInsertionLine(unsigned LineNo,const SourceColumnMap & map,ArrayRef<FixItHint> Hints,const SourceManager & SM,const DiagnosticOptions * DiagOpts)994*67e74705SXin Li static std::string buildFixItInsertionLine(unsigned LineNo,
995*67e74705SXin Li const SourceColumnMap &map,
996*67e74705SXin Li ArrayRef<FixItHint> Hints,
997*67e74705SXin Li const SourceManager &SM,
998*67e74705SXin Li const DiagnosticOptions *DiagOpts) {
999*67e74705SXin Li std::string FixItInsertionLine;
1000*67e74705SXin Li if (Hints.empty() || !DiagOpts->ShowFixits)
1001*67e74705SXin Li return FixItInsertionLine;
1002*67e74705SXin Li unsigned PrevHintEndCol = 0;
1003*67e74705SXin Li
1004*67e74705SXin Li for (ArrayRef<FixItHint>::iterator I = Hints.begin(), E = Hints.end();
1005*67e74705SXin Li I != E; ++I) {
1006*67e74705SXin Li if (!I->CodeToInsert.empty()) {
1007*67e74705SXin Li // We have an insertion hint. Determine whether the inserted
1008*67e74705SXin Li // code contains no newlines and is on the same line as the caret.
1009*67e74705SXin Li std::pair<FileID, unsigned> HintLocInfo
1010*67e74705SXin Li = SM.getDecomposedExpansionLoc(I->RemoveRange.getBegin());
1011*67e74705SXin Li if (LineNo == SM.getLineNumber(HintLocInfo.first, HintLocInfo.second) &&
1012*67e74705SXin Li StringRef(I->CodeToInsert).find_first_of("\n\r") == StringRef::npos) {
1013*67e74705SXin Li // Insert the new code into the line just below the code
1014*67e74705SXin Li // that the user wrote.
1015*67e74705SXin Li // Note: When modifying this function, be very careful about what is a
1016*67e74705SXin Li // "column" (printed width, platform-dependent) and what is a
1017*67e74705SXin Li // "byte offset" (SourceManager "column").
1018*67e74705SXin Li unsigned HintByteOffset
1019*67e74705SXin Li = SM.getColumnNumber(HintLocInfo.first, HintLocInfo.second) - 1;
1020*67e74705SXin Li
1021*67e74705SXin Li // The hint must start inside the source or right at the end
1022*67e74705SXin Li assert(HintByteOffset < static_cast<unsigned>(map.bytes())+1);
1023*67e74705SXin Li unsigned HintCol = map.byteToContainingColumn(HintByteOffset);
1024*67e74705SXin Li
1025*67e74705SXin Li // If we inserted a long previous hint, push this one forwards, and add
1026*67e74705SXin Li // an extra space to show that this is not part of the previous
1027*67e74705SXin Li // completion. This is sort of the best we can do when two hints appear
1028*67e74705SXin Li // to overlap.
1029*67e74705SXin Li //
1030*67e74705SXin Li // Note that if this hint is located immediately after the previous
1031*67e74705SXin Li // hint, no space will be added, since the location is more important.
1032*67e74705SXin Li if (HintCol < PrevHintEndCol)
1033*67e74705SXin Li HintCol = PrevHintEndCol + 1;
1034*67e74705SXin Li
1035*67e74705SXin Li // This should NOT use HintByteOffset, because the source might have
1036*67e74705SXin Li // Unicode characters in earlier columns.
1037*67e74705SXin Li unsigned NewFixItLineSize = FixItInsertionLine.size() +
1038*67e74705SXin Li (HintCol - PrevHintEndCol) + I->CodeToInsert.size();
1039*67e74705SXin Li if (NewFixItLineSize > FixItInsertionLine.size())
1040*67e74705SXin Li FixItInsertionLine.resize(NewFixItLineSize, ' ');
1041*67e74705SXin Li
1042*67e74705SXin Li std::copy(I->CodeToInsert.begin(), I->CodeToInsert.end(),
1043*67e74705SXin Li FixItInsertionLine.end() - I->CodeToInsert.size());
1044*67e74705SXin Li
1045*67e74705SXin Li PrevHintEndCol =
1046*67e74705SXin Li HintCol + llvm::sys::locale::columnWidth(I->CodeToInsert);
1047*67e74705SXin Li } else {
1048*67e74705SXin Li FixItInsertionLine.clear();
1049*67e74705SXin Li break;
1050*67e74705SXin Li }
1051*67e74705SXin Li }
1052*67e74705SXin Li }
1053*67e74705SXin Li
1054*67e74705SXin Li expandTabs(FixItInsertionLine, DiagOpts->TabStop);
1055*67e74705SXin Li
1056*67e74705SXin Li return FixItInsertionLine;
1057*67e74705SXin Li }
1058*67e74705SXin Li
1059*67e74705SXin Li /// \brief Emit a code snippet and caret line.
1060*67e74705SXin Li ///
1061*67e74705SXin Li /// This routine emits a single line's code snippet and caret line..
1062*67e74705SXin Li ///
1063*67e74705SXin Li /// \param Loc The location for the caret.
1064*67e74705SXin Li /// \param Ranges The underlined ranges for this code snippet.
1065*67e74705SXin Li /// \param Hints The FixIt hints active for this diagnostic.
emitSnippetAndCaret(SourceLocation Loc,DiagnosticsEngine::Level Level,SmallVectorImpl<CharSourceRange> & Ranges,ArrayRef<FixItHint> Hints,const SourceManager & SM)1066*67e74705SXin Li void TextDiagnostic::emitSnippetAndCaret(
1067*67e74705SXin Li SourceLocation Loc, DiagnosticsEngine::Level Level,
1068*67e74705SXin Li SmallVectorImpl<CharSourceRange>& Ranges,
1069*67e74705SXin Li ArrayRef<FixItHint> Hints,
1070*67e74705SXin Li const SourceManager &SM) {
1071*67e74705SXin Li assert(Loc.isValid() && "must have a valid source location here");
1072*67e74705SXin Li assert(Loc.isFileID() && "must have a file location here");
1073*67e74705SXin Li
1074*67e74705SXin Li // If caret diagnostics are enabled and we have location, we want to
1075*67e74705SXin Li // emit the caret. However, we only do this if the location moved
1076*67e74705SXin Li // from the last diagnostic, if the last diagnostic was a note that
1077*67e74705SXin Li // was part of a different warning or error diagnostic, or if the
1078*67e74705SXin Li // diagnostic has ranges. We don't want to emit the same caret
1079*67e74705SXin Li // multiple times if one loc has multiple diagnostics.
1080*67e74705SXin Li if (!DiagOpts->ShowCarets)
1081*67e74705SXin Li return;
1082*67e74705SXin Li if (Loc == LastLoc && Ranges.empty() && Hints.empty() &&
1083*67e74705SXin Li (LastLevel != DiagnosticsEngine::Note || Level == LastLevel))
1084*67e74705SXin Li return;
1085*67e74705SXin Li
1086*67e74705SXin Li // Decompose the location into a FID/Offset pair.
1087*67e74705SXin Li std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
1088*67e74705SXin Li FileID FID = LocInfo.first;
1089*67e74705SXin Li unsigned FileOffset = LocInfo.second;
1090*67e74705SXin Li
1091*67e74705SXin Li // Get information about the buffer it points into.
1092*67e74705SXin Li bool Invalid = false;
1093*67e74705SXin Li StringRef BufData = SM.getBufferData(FID, &Invalid);
1094*67e74705SXin Li if (Invalid)
1095*67e74705SXin Li return;
1096*67e74705SXin Li
1097*67e74705SXin Li const char *BufStart = BufData.data();
1098*67e74705SXin Li const char *BufEnd = BufStart + BufData.size();
1099*67e74705SXin Li
1100*67e74705SXin Li unsigned LineNo = SM.getLineNumber(FID, FileOffset);
1101*67e74705SXin Li unsigned ColNo = SM.getColumnNumber(FID, FileOffset);
1102*67e74705SXin Li
1103*67e74705SXin Li // Arbitrarily stop showing snippets when the line is too long.
1104*67e74705SXin Li static const size_t MaxLineLengthToPrint = 4096;
1105*67e74705SXin Li if (ColNo > MaxLineLengthToPrint)
1106*67e74705SXin Li return;
1107*67e74705SXin Li
1108*67e74705SXin Li // Rewind from the current position to the start of the line.
1109*67e74705SXin Li const char *TokPtr = BufStart+FileOffset;
1110*67e74705SXin Li const char *LineStart = TokPtr-ColNo+1; // Column # is 1-based.
1111*67e74705SXin Li
1112*67e74705SXin Li // Compute the line end. Scan forward from the error position to the end of
1113*67e74705SXin Li // the line.
1114*67e74705SXin Li const char *LineEnd = TokPtr;
1115*67e74705SXin Li while (*LineEnd != '\n' && *LineEnd != '\r' && LineEnd != BufEnd)
1116*67e74705SXin Li ++LineEnd;
1117*67e74705SXin Li
1118*67e74705SXin Li // Arbitrarily stop showing snippets when the line is too long.
1119*67e74705SXin Li if (size_t(LineEnd - LineStart) > MaxLineLengthToPrint)
1120*67e74705SXin Li return;
1121*67e74705SXin Li
1122*67e74705SXin Li // Trim trailing null-bytes.
1123*67e74705SXin Li StringRef Line(LineStart, LineEnd - LineStart);
1124*67e74705SXin Li while (Line.size() > ColNo && Line.back() == '\0')
1125*67e74705SXin Li Line = Line.drop_back();
1126*67e74705SXin Li
1127*67e74705SXin Li // Copy the line of code into an std::string for ease of manipulation.
1128*67e74705SXin Li std::string SourceLine(Line.begin(), Line.end());
1129*67e74705SXin Li
1130*67e74705SXin Li // Build the byte to column map.
1131*67e74705SXin Li const SourceColumnMap sourceColMap(SourceLine, DiagOpts->TabStop);
1132*67e74705SXin Li
1133*67e74705SXin Li // Create a line for the caret that is filled with spaces that is the same
1134*67e74705SXin Li // number of columns as the line of source code.
1135*67e74705SXin Li std::string CaretLine(sourceColMap.columns(), ' ');
1136*67e74705SXin Li
1137*67e74705SXin Li // Highlight all of the characters covered by Ranges with ~ characters.
1138*67e74705SXin Li for (SmallVectorImpl<CharSourceRange>::iterator I = Ranges.begin(),
1139*67e74705SXin Li E = Ranges.end();
1140*67e74705SXin Li I != E; ++I)
1141*67e74705SXin Li highlightRange(*I, LineNo, FID, sourceColMap, CaretLine, SM, LangOpts);
1142*67e74705SXin Li
1143*67e74705SXin Li // Next, insert the caret itself.
1144*67e74705SXin Li ColNo = sourceColMap.byteToContainingColumn(ColNo-1);
1145*67e74705SXin Li if (CaretLine.size()<ColNo+1)
1146*67e74705SXin Li CaretLine.resize(ColNo+1, ' ');
1147*67e74705SXin Li CaretLine[ColNo] = '^';
1148*67e74705SXin Li
1149*67e74705SXin Li std::string FixItInsertionLine = buildFixItInsertionLine(LineNo,
1150*67e74705SXin Li sourceColMap,
1151*67e74705SXin Li Hints, SM,
1152*67e74705SXin Li DiagOpts.get());
1153*67e74705SXin Li
1154*67e74705SXin Li // If the source line is too long for our terminal, select only the
1155*67e74705SXin Li // "interesting" source region within that line.
1156*67e74705SXin Li unsigned Columns = DiagOpts->MessageLength;
1157*67e74705SXin Li if (Columns)
1158*67e74705SXin Li selectInterestingSourceRegion(SourceLine, CaretLine, FixItInsertionLine,
1159*67e74705SXin Li Columns, sourceColMap);
1160*67e74705SXin Li
1161*67e74705SXin Li // If we are in -fdiagnostics-print-source-range-info mode, we are trying
1162*67e74705SXin Li // to produce easily machine parsable output. Add a space before the
1163*67e74705SXin Li // source line and the caret to make it trivial to tell the main diagnostic
1164*67e74705SXin Li // line from what the user is intended to see.
1165*67e74705SXin Li if (DiagOpts->ShowSourceRanges) {
1166*67e74705SXin Li SourceLine = ' ' + SourceLine;
1167*67e74705SXin Li CaretLine = ' ' + CaretLine;
1168*67e74705SXin Li }
1169*67e74705SXin Li
1170*67e74705SXin Li // Finally, remove any blank spaces from the end of CaretLine.
1171*67e74705SXin Li while (CaretLine[CaretLine.size()-1] == ' ')
1172*67e74705SXin Li CaretLine.erase(CaretLine.end()-1);
1173*67e74705SXin Li
1174*67e74705SXin Li // Emit what we have computed.
1175*67e74705SXin Li emitSnippet(SourceLine);
1176*67e74705SXin Li
1177*67e74705SXin Li if (DiagOpts->ShowColors)
1178*67e74705SXin Li OS.changeColor(caretColor, true);
1179*67e74705SXin Li OS << CaretLine << '\n';
1180*67e74705SXin Li if (DiagOpts->ShowColors)
1181*67e74705SXin Li OS.resetColor();
1182*67e74705SXin Li
1183*67e74705SXin Li if (!FixItInsertionLine.empty()) {
1184*67e74705SXin Li if (DiagOpts->ShowColors)
1185*67e74705SXin Li // Print fixit line in color
1186*67e74705SXin Li OS.changeColor(fixitColor, false);
1187*67e74705SXin Li if (DiagOpts->ShowSourceRanges)
1188*67e74705SXin Li OS << ' ';
1189*67e74705SXin Li OS << FixItInsertionLine << '\n';
1190*67e74705SXin Li if (DiagOpts->ShowColors)
1191*67e74705SXin Li OS.resetColor();
1192*67e74705SXin Li }
1193*67e74705SXin Li
1194*67e74705SXin Li // Print out any parseable fixit information requested by the options.
1195*67e74705SXin Li emitParseableFixits(Hints, SM);
1196*67e74705SXin Li }
1197*67e74705SXin Li
emitSnippet(StringRef line)1198*67e74705SXin Li void TextDiagnostic::emitSnippet(StringRef line) {
1199*67e74705SXin Li if (line.empty())
1200*67e74705SXin Li return;
1201*67e74705SXin Li
1202*67e74705SXin Li size_t i = 0;
1203*67e74705SXin Li
1204*67e74705SXin Li std::string to_print;
1205*67e74705SXin Li bool print_reversed = false;
1206*67e74705SXin Li
1207*67e74705SXin Li while (i<line.size()) {
1208*67e74705SXin Li std::pair<SmallString<16>,bool> res
1209*67e74705SXin Li = printableTextForNextCharacter(line, &i, DiagOpts->TabStop);
1210*67e74705SXin Li bool was_printable = res.second;
1211*67e74705SXin Li
1212*67e74705SXin Li if (DiagOpts->ShowColors && was_printable == print_reversed) {
1213*67e74705SXin Li if (print_reversed)
1214*67e74705SXin Li OS.reverseColor();
1215*67e74705SXin Li OS << to_print;
1216*67e74705SXin Li to_print.clear();
1217*67e74705SXin Li if (DiagOpts->ShowColors)
1218*67e74705SXin Li OS.resetColor();
1219*67e74705SXin Li }
1220*67e74705SXin Li
1221*67e74705SXin Li print_reversed = !was_printable;
1222*67e74705SXin Li to_print += res.first.str();
1223*67e74705SXin Li }
1224*67e74705SXin Li
1225*67e74705SXin Li if (print_reversed && DiagOpts->ShowColors)
1226*67e74705SXin Li OS.reverseColor();
1227*67e74705SXin Li OS << to_print;
1228*67e74705SXin Li if (print_reversed && DiagOpts->ShowColors)
1229*67e74705SXin Li OS.resetColor();
1230*67e74705SXin Li
1231*67e74705SXin Li OS << '\n';
1232*67e74705SXin Li }
1233*67e74705SXin Li
emitParseableFixits(ArrayRef<FixItHint> Hints,const SourceManager & SM)1234*67e74705SXin Li void TextDiagnostic::emitParseableFixits(ArrayRef<FixItHint> Hints,
1235*67e74705SXin Li const SourceManager &SM) {
1236*67e74705SXin Li if (!DiagOpts->ShowParseableFixits)
1237*67e74705SXin Li return;
1238*67e74705SXin Li
1239*67e74705SXin Li // We follow FixItRewriter's example in not (yet) handling
1240*67e74705SXin Li // fix-its in macros.
1241*67e74705SXin Li for (ArrayRef<FixItHint>::iterator I = Hints.begin(), E = Hints.end();
1242*67e74705SXin Li I != E; ++I) {
1243*67e74705SXin Li if (I->RemoveRange.isInvalid() ||
1244*67e74705SXin Li I->RemoveRange.getBegin().isMacroID() ||
1245*67e74705SXin Li I->RemoveRange.getEnd().isMacroID())
1246*67e74705SXin Li return;
1247*67e74705SXin Li }
1248*67e74705SXin Li
1249*67e74705SXin Li for (ArrayRef<FixItHint>::iterator I = Hints.begin(), E = Hints.end();
1250*67e74705SXin Li I != E; ++I) {
1251*67e74705SXin Li SourceLocation BLoc = I->RemoveRange.getBegin();
1252*67e74705SXin Li SourceLocation ELoc = I->RemoveRange.getEnd();
1253*67e74705SXin Li
1254*67e74705SXin Li std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(BLoc);
1255*67e74705SXin Li std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(ELoc);
1256*67e74705SXin Li
1257*67e74705SXin Li // Adjust for token ranges.
1258*67e74705SXin Li if (I->RemoveRange.isTokenRange())
1259*67e74705SXin Li EInfo.second += Lexer::MeasureTokenLength(ELoc, SM, LangOpts);
1260*67e74705SXin Li
1261*67e74705SXin Li // We specifically do not do word-wrapping or tab-expansion here,
1262*67e74705SXin Li // because this is supposed to be easy to parse.
1263*67e74705SXin Li PresumedLoc PLoc = SM.getPresumedLoc(BLoc);
1264*67e74705SXin Li if (PLoc.isInvalid())
1265*67e74705SXin Li break;
1266*67e74705SXin Li
1267*67e74705SXin Li OS << "fix-it:\"";
1268*67e74705SXin Li OS.write_escaped(PLoc.getFilename());
1269*67e74705SXin Li OS << "\":{" << SM.getLineNumber(BInfo.first, BInfo.second)
1270*67e74705SXin Li << ':' << SM.getColumnNumber(BInfo.first, BInfo.second)
1271*67e74705SXin Li << '-' << SM.getLineNumber(EInfo.first, EInfo.second)
1272*67e74705SXin Li << ':' << SM.getColumnNumber(EInfo.first, EInfo.second)
1273*67e74705SXin Li << "}:\"";
1274*67e74705SXin Li OS.write_escaped(I->CodeToInsert);
1275*67e74705SXin Li OS << "\"\n";
1276*67e74705SXin Li }
1277*67e74705SXin Li }
1278