TextDiagnosticPrinter.cpp revision 4786c15f4977c7cee98fde3ebdee213dba23848b
1//===--- TextDiagnosticPrinter.cpp - Diagnostic Printer -------------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This diagnostic client prints out their diagnostic messages.
11//
12//===----------------------------------------------------------------------===//
13
14#include "clang/Frontend/TextDiagnosticPrinter.h"
15#include "clang/Basic/SourceManager.h"
16#include "clang/Frontend/DiagnosticOptions.h"
17#include "clang/Lex/Lexer.h"
18#include "llvm/Support/MemoryBuffer.h"
19#include "llvm/Support/raw_ostream.h"
20#include "llvm/ADT/SmallString.h"
21#include "llvm/ADT/StringExtras.h"
22#include <algorithm>
23using namespace clang;
24
25static const enum llvm::raw_ostream::Colors noteColor =
26  llvm::raw_ostream::BLACK;
27static const enum llvm::raw_ostream::Colors fixitColor =
28  llvm::raw_ostream::GREEN;
29static const enum llvm::raw_ostream::Colors caretColor =
30  llvm::raw_ostream::GREEN;
31static const enum llvm::raw_ostream::Colors warningColor =
32  llvm::raw_ostream::MAGENTA;
33static const enum llvm::raw_ostream::Colors errorColor = llvm::raw_ostream::RED;
34static const enum llvm::raw_ostream::Colors fatalColor = llvm::raw_ostream::RED;
35// Used for changing only the bold attribute.
36static const enum llvm::raw_ostream::Colors savedColor =
37  llvm::raw_ostream::SAVEDCOLOR;
38
39/// \brief Number of spaces to indent when word-wrapping.
40const unsigned WordWrapIndentation = 6;
41
42TextDiagnosticPrinter::TextDiagnosticPrinter(llvm::raw_ostream &os,
43                                             const DiagnosticOptions &diags,
44                                             bool _OwnsOutputStream)
45  : OS(os), LangOpts(0), DiagOpts(&diags),
46    LastCaretDiagnosticWasNote(0),
47    OwnsOutputStream(_OwnsOutputStream) {
48}
49
50TextDiagnosticPrinter::~TextDiagnosticPrinter() {
51  if (OwnsOutputStream)
52    delete &OS;
53}
54
55void TextDiagnosticPrinter::
56PrintIncludeStack(SourceLocation Loc, const SourceManager &SM) {
57  if (Loc.isInvalid()) return;
58
59  PresumedLoc PLoc = SM.getPresumedLoc(Loc);
60
61  // Print out the other include frames first.
62  PrintIncludeStack(PLoc.getIncludeLoc(), SM);
63
64  if (DiagOpts->ShowLocation)
65    OS << "In file included from " << PLoc.getFilename()
66       << ':' << PLoc.getLine() << ":\n";
67  else
68    OS << "In included file:\n";
69}
70
71/// HighlightRange - Given a SourceRange and a line number, highlight (with ~'s)
72/// any characters in LineNo that intersect the SourceRange.
73void TextDiagnosticPrinter::HighlightRange(const CharSourceRange &R,
74                                           const SourceManager &SM,
75                                           unsigned LineNo, FileID FID,
76                                           std::string &CaretLine,
77                                           const std::string &SourceLine) {
78  assert(CaretLine.size() == SourceLine.size() &&
79         "Expect a correspondence between source and caret line!");
80  if (!R.isValid()) return;
81
82  SourceLocation Begin = SM.getInstantiationLoc(R.getBegin());
83  SourceLocation End = SM.getInstantiationLoc(R.getEnd());
84
85  // If the End location and the start location are the same and are a macro
86  // location, then the range was something that came from a macro expansion
87  // or _Pragma.  If this is an object-like macro, the best we can do is to
88  // highlight the range.  If this is a function-like macro, we'd also like to
89  // highlight the arguments.
90  if (Begin == End && R.getEnd().isMacroID())
91    End = SM.getInstantiationRange(R.getEnd()).second;
92
93  unsigned StartLineNo = SM.getInstantiationLineNumber(Begin);
94  if (StartLineNo > LineNo || SM.getFileID(Begin) != FID)
95    return;  // No intersection.
96
97  unsigned EndLineNo = SM.getInstantiationLineNumber(End);
98  if (EndLineNo < LineNo || SM.getFileID(End) != FID)
99    return;  // No intersection.
100
101  // Compute the column number of the start.
102  unsigned StartColNo = 0;
103  if (StartLineNo == LineNo) {
104    StartColNo = SM.getInstantiationColumnNumber(Begin);
105    if (StartColNo) --StartColNo;  // Zero base the col #.
106  }
107
108  // Compute the column number of the end.
109  unsigned EndColNo = CaretLine.size();
110  if (EndLineNo == LineNo) {
111    EndColNo = SM.getInstantiationColumnNumber(End);
112    if (EndColNo) {
113      --EndColNo;  // Zero base the col #.
114
115      // Add in the length of the token, so that we cover multi-char tokens if
116      // this is a token range.
117      if (R.isTokenRange())
118        EndColNo += Lexer::MeasureTokenLength(End, SM, *LangOpts);
119    } else {
120      EndColNo = CaretLine.size();
121    }
122  }
123
124  assert(StartColNo <= EndColNo && "Invalid range!");
125
126  // Check that a token range does not highlight only whitespace.
127  if (R.isTokenRange()) {
128    // Pick the first non-whitespace column.
129    while (StartColNo < SourceLine.size() &&
130           (SourceLine[StartColNo] == ' ' || SourceLine[StartColNo] == '\t'))
131      ++StartColNo;
132
133    // Pick the last non-whitespace column.
134    if (EndColNo > SourceLine.size())
135      EndColNo = SourceLine.size();
136    while (EndColNo-1 &&
137           (SourceLine[EndColNo-1] == ' ' || SourceLine[EndColNo-1] == '\t'))
138      --EndColNo;
139
140    // If the start/end passed each other, then we are trying to highlight a range
141    // that just exists in whitespace, which must be some sort of other bug.
142    assert(StartColNo <= EndColNo && "Trying to highlight whitespace??");
143  }
144
145  // Fill the range with ~'s.
146  for (unsigned i = StartColNo; i < EndColNo; ++i)
147    CaretLine[i] = '~';
148}
149
150/// \brief When the source code line we want to print is too long for
151/// the terminal, select the "interesting" region.
152static void SelectInterestingSourceRegion(std::string &SourceLine,
153                                          std::string &CaretLine,
154                                          std::string &FixItInsertionLine,
155                                          unsigned EndOfCaretToken,
156                                          unsigned Columns) {
157  unsigned MaxSize = std::max(SourceLine.size(),
158                              std::max(CaretLine.size(),
159                                       FixItInsertionLine.size()));
160  if (MaxSize > SourceLine.size())
161    SourceLine.resize(MaxSize, ' ');
162  if (MaxSize > CaretLine.size())
163    CaretLine.resize(MaxSize, ' ');
164  if (!FixItInsertionLine.empty() && MaxSize > FixItInsertionLine.size())
165    FixItInsertionLine.resize(MaxSize, ' ');
166
167  // Find the slice that we need to display the full caret line
168  // correctly.
169  unsigned CaretStart = 0, CaretEnd = CaretLine.size();
170  for (; CaretStart != CaretEnd; ++CaretStart)
171    if (!isspace(CaretLine[CaretStart]))
172      break;
173
174  for (; CaretEnd != CaretStart; --CaretEnd)
175    if (!isspace(CaretLine[CaretEnd - 1]))
176      break;
177
178  // Make sure we don't chop the string shorter than the caret token
179  // itself.
180  if (CaretEnd < EndOfCaretToken)
181    CaretEnd = EndOfCaretToken;
182
183  // If we have a fix-it line, make sure the slice includes all of the
184  // fix-it information.
185  if (!FixItInsertionLine.empty()) {
186    unsigned FixItStart = 0, FixItEnd = FixItInsertionLine.size();
187    for (; FixItStart != FixItEnd; ++FixItStart)
188      if (!isspace(FixItInsertionLine[FixItStart]))
189        break;
190
191    for (; FixItEnd != FixItStart; --FixItEnd)
192      if (!isspace(FixItInsertionLine[FixItEnd - 1]))
193        break;
194
195    if (FixItStart < CaretStart)
196      CaretStart = FixItStart;
197    if (FixItEnd > CaretEnd)
198      CaretEnd = FixItEnd;
199  }
200
201  // CaretLine[CaretStart, CaretEnd) contains all of the interesting
202  // parts of the caret line. While this slice is smaller than the
203  // number of columns we have, try to grow the slice to encompass
204  // more context.
205
206  // If the end of the interesting region comes before we run out of
207  // space in the terminal, start at the beginning of the line.
208  if (Columns > 3 && CaretEnd < Columns - 3)
209    CaretStart = 0;
210
211  unsigned TargetColumns = Columns;
212  if (TargetColumns > 8)
213    TargetColumns -= 8; // Give us extra room for the ellipses.
214  unsigned SourceLength = SourceLine.size();
215  while ((CaretEnd - CaretStart) < TargetColumns) {
216    bool ExpandedRegion = false;
217    // Move the start of the interesting region left until we've
218    // pulled in something else interesting.
219    if (CaretStart == 1)
220      CaretStart = 0;
221    else if (CaretStart > 1) {
222      unsigned NewStart = CaretStart - 1;
223
224      // Skip over any whitespace we see here; we're looking for
225      // another bit of interesting text.
226      while (NewStart && isspace(SourceLine[NewStart]))
227        --NewStart;
228
229      // Skip over this bit of "interesting" text.
230      while (NewStart && !isspace(SourceLine[NewStart]))
231        --NewStart;
232
233      // Move up to the non-whitespace character we just saw.
234      if (NewStart)
235        ++NewStart;
236
237      // If we're still within our limit, update the starting
238      // position within the source/caret line.
239      if (CaretEnd - NewStart <= TargetColumns) {
240        CaretStart = NewStart;
241        ExpandedRegion = true;
242      }
243    }
244
245    // Move the end of the interesting region right until we've
246    // pulled in something else interesting.
247    if (CaretEnd != SourceLength) {
248      assert(CaretEnd < SourceLength && "Unexpected caret position!");
249      unsigned NewEnd = CaretEnd;
250
251      // Skip over any whitespace we see here; we're looking for
252      // another bit of interesting text.
253      while (NewEnd != SourceLength && isspace(SourceLine[NewEnd - 1]))
254        ++NewEnd;
255
256      // Skip over this bit of "interesting" text.
257      while (NewEnd != SourceLength && !isspace(SourceLine[NewEnd - 1]))
258        ++NewEnd;
259
260      if (NewEnd - CaretStart <= TargetColumns) {
261        CaretEnd = NewEnd;
262        ExpandedRegion = true;
263      }
264    }
265
266    if (!ExpandedRegion)
267      break;
268  }
269
270  // [CaretStart, CaretEnd) is the slice we want. Update the various
271  // output lines to show only this slice, with two-space padding
272  // before the lines so that it looks nicer.
273  if (CaretEnd < SourceLine.size())
274    SourceLine.replace(CaretEnd, std::string::npos, "...");
275  if (CaretEnd < CaretLine.size())
276    CaretLine.erase(CaretEnd, std::string::npos);
277  if (FixItInsertionLine.size() > CaretEnd)
278    FixItInsertionLine.erase(CaretEnd, std::string::npos);
279
280  if (CaretStart > 2) {
281    SourceLine.replace(0, CaretStart, "  ...");
282    CaretLine.replace(0, CaretStart, "     ");
283    if (FixItInsertionLine.size() >= CaretStart)
284      FixItInsertionLine.replace(0, CaretStart, "     ");
285  }
286}
287
288void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc,
289                                                CharSourceRange *Ranges,
290                                                unsigned NumRanges,
291                                                const SourceManager &SM,
292                                                const FixItHint *Hints,
293                                                unsigned NumHints,
294                                                unsigned Columns,
295                                                unsigned OnMacroInst,
296                                                unsigned MacroSkipStart,
297                                                unsigned MacroSkipEnd) {
298  assert(LangOpts && "Unexpected diagnostic outside source file processing");
299  assert(!Loc.isInvalid() && "must have a valid source location here");
300
301  // If this is a macro ID, first emit information about where this was
302  // instantiated (recursively) then emit information about where the token was
303  // spelled from.
304  if (!Loc.isFileID()) {
305    // Whether to suppress printing this macro instantiation.
306    bool Suppressed
307      = OnMacroInst >= MacroSkipStart && OnMacroInst < MacroSkipEnd;
308
309
310    SourceLocation OneLevelUp = SM.getImmediateInstantiationRange(Loc).first;
311    // FIXME: Map ranges?
312    EmitCaretDiagnostic(OneLevelUp, Ranges, NumRanges, SM, 0, 0, Columns,
313                        OnMacroInst + 1, MacroSkipStart, MacroSkipEnd);
314
315    // Map the location.
316    Loc = SM.getImmediateSpellingLoc(Loc);
317
318    // Map the ranges.
319    for (unsigned i = 0; i != NumRanges; ++i) {
320      CharSourceRange &R = Ranges[i];
321      SourceLocation S = R.getBegin(), E = R.getEnd();
322      if (S.isMacroID())
323        R.setBegin(SM.getImmediateSpellingLoc(S));
324      if (E.isMacroID())
325        R.setEnd(SM.getImmediateSpellingLoc(E));
326    }
327
328    if (!Suppressed) {
329      // Get the pretty name, according to #line directives etc.
330      PresumedLoc PLoc = SM.getPresumedLoc(Loc);
331
332      // If this diagnostic is not in the main file, print out the
333      // "included from" lines.
334      if (LastWarningLoc != PLoc.getIncludeLoc()) {
335        LastWarningLoc = PLoc.getIncludeLoc();
336        PrintIncludeStack(LastWarningLoc, SM);
337      }
338
339      if (DiagOpts->ShowLocation) {
340        // Emit the file/line/column that this expansion came from.
341        OS << PLoc.getFilename() << ':' << PLoc.getLine() << ':';
342        if (DiagOpts->ShowColumn)
343          OS << PLoc.getColumn() << ':';
344        OS << ' ';
345      }
346      OS << "note: instantiated from:\n";
347
348      EmitCaretDiagnostic(Loc, Ranges, NumRanges, SM, Hints, NumHints, Columns,
349                          OnMacroInst + 1, MacroSkipStart, MacroSkipEnd);
350      return;
351    }
352
353    if (OnMacroInst == MacroSkipStart) {
354      // Tell the user that we've skipped contexts.
355      OS << "note: (skipping " << (MacroSkipEnd - MacroSkipStart)
356      << " contexts in backtrace; use -fmacro-backtrace-limit=0 to see "
357      "all)\n";
358    }
359
360    return;
361  }
362
363  // Decompose the location into a FID/Offset pair.
364  std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
365  FileID FID = LocInfo.first;
366  unsigned FileOffset = LocInfo.second;
367
368  // Get information about the buffer it points into.
369  bool Invalid = false;
370  const char *BufStart = SM.getBufferData(FID, &Invalid).data();
371  if (Invalid)
372    return;
373
374  unsigned ColNo = SM.getColumnNumber(FID, FileOffset);
375  unsigned CaretEndColNo
376    = ColNo + Lexer::MeasureTokenLength(Loc, SM, *LangOpts);
377
378  // Rewind from the current position to the start of the line.
379  const char *TokPtr = BufStart+FileOffset;
380  const char *LineStart = TokPtr-ColNo+1; // Column # is 1-based.
381
382
383  // Compute the line end.  Scan forward from the error position to the end of
384  // the line.
385  const char *LineEnd = TokPtr;
386  while (*LineEnd != '\n' && *LineEnd != '\r' && *LineEnd != '\0')
387    ++LineEnd;
388
389  // FIXME: This shouldn't be necessary, but the CaretEndColNo can extend past
390  // the source line length as currently being computed. See
391  // test/Misc/message-length.c.
392  CaretEndColNo = std::min(CaretEndColNo, unsigned(LineEnd - LineStart));
393
394  // Copy the line of code into an std::string for ease of manipulation.
395  std::string SourceLine(LineStart, LineEnd);
396
397  // Create a line for the caret that is filled with spaces that is the same
398  // length as the line of source code.
399  std::string CaretLine(LineEnd-LineStart, ' ');
400
401  // Highlight all of the characters covered by Ranges with ~ characters.
402  if (NumRanges) {
403    unsigned LineNo = SM.getLineNumber(FID, FileOffset);
404
405    for (unsigned i = 0, e = NumRanges; i != e; ++i)
406      HighlightRange(Ranges[i], SM, LineNo, FID, CaretLine, SourceLine);
407  }
408
409  // Next, insert the caret itself.
410  if (ColNo-1 < CaretLine.size())
411    CaretLine[ColNo-1] = '^';
412  else
413    CaretLine.push_back('^');
414
415  // Scan the source line, looking for tabs.  If we find any, manually expand
416  // them to spaces and update the CaretLine to match.
417  for (unsigned i = 0; i != SourceLine.size(); ++i) {
418    if (SourceLine[i] != '\t') continue;
419
420    // Replace this tab with at least one space.
421    SourceLine[i] = ' ';
422
423    // Compute the number of spaces we need to insert.
424    unsigned TabStop = DiagOpts->TabStop;
425    assert(0 < TabStop && TabStop <= DiagnosticOptions::MaxTabStop &&
426           "Invalid -ftabstop value");
427    unsigned NumSpaces = ((i+TabStop)/TabStop * TabStop) - (i+1);
428    assert(NumSpaces < TabStop && "Invalid computation of space amt");
429
430    // Insert spaces into the SourceLine.
431    SourceLine.insert(i+1, NumSpaces, ' ');
432
433    // Insert spaces or ~'s into CaretLine.
434    CaretLine.insert(i+1, NumSpaces, CaretLine[i] == '~' ? '~' : ' ');
435  }
436
437  // If we are in -fdiagnostics-print-source-range-info mode, we are trying to
438  // produce easily machine parsable output.  Add a space before the source line
439  // and the caret to make it trivial to tell the main diagnostic line from what
440  // the user is intended to see.
441  if (DiagOpts->ShowSourceRanges) {
442    SourceLine = ' ' + SourceLine;
443    CaretLine = ' ' + CaretLine;
444  }
445
446  std::string FixItInsertionLine;
447  if (NumHints && DiagOpts->ShowFixits) {
448    for (const FixItHint *Hint = Hints, *LastHint = Hints + NumHints;
449         Hint != LastHint; ++Hint) {
450      if (!Hint->CodeToInsert.empty()) {
451        // We have an insertion hint. Determine whether the inserted
452        // code is on the same line as the caret.
453        std::pair<FileID, unsigned> HintLocInfo
454          = SM.getDecomposedInstantiationLoc(Hint->RemoveRange.getBegin());
455        if (SM.getLineNumber(HintLocInfo.first, HintLocInfo.second) ==
456              SM.getLineNumber(FID, FileOffset)) {
457          // Insert the new code into the line just below the code
458          // that the user wrote.
459          unsigned HintColNo
460            = SM.getColumnNumber(HintLocInfo.first, HintLocInfo.second);
461          unsigned LastColumnModified
462            = HintColNo - 1 + Hint->CodeToInsert.size();
463          if (LastColumnModified > FixItInsertionLine.size())
464            FixItInsertionLine.resize(LastColumnModified, ' ');
465          std::copy(Hint->CodeToInsert.begin(), Hint->CodeToInsert.end(),
466                    FixItInsertionLine.begin() + HintColNo - 1);
467        } else {
468          FixItInsertionLine.clear();
469          break;
470        }
471      }
472    }
473    // Now that we have the entire fixit line, expand the tabs in it.
474    // Since we don't want to insert spaces in the middle of a word,
475    // find each word and the column it should line up with and insert
476    // spaces until they match.
477    if (!FixItInsertionLine.empty()) {
478      unsigned FixItPos = 0;
479      unsigned LinePos = 0;
480      unsigned TabExpandedCol = 0;
481      unsigned LineLength = LineEnd - LineStart;
482
483      while (FixItPos < FixItInsertionLine.size() && LinePos < LineLength) {
484        // Find the next word in the FixIt line.
485        while (FixItPos < FixItInsertionLine.size() &&
486               FixItInsertionLine[FixItPos] == ' ')
487          ++FixItPos;
488        unsigned CharDistance = FixItPos - TabExpandedCol;
489
490        // Walk forward in the source line, keeping track of
491        // the tab-expanded column.
492        for (unsigned I = 0; I < CharDistance; ++I, ++LinePos)
493          if (LinePos >= LineLength || LineStart[LinePos] != '\t')
494            ++TabExpandedCol;
495          else
496            TabExpandedCol =
497              (TabExpandedCol/DiagOpts->TabStop + 1) * DiagOpts->TabStop;
498
499        // Adjust the fixit line to match this column.
500        FixItInsertionLine.insert(FixItPos, TabExpandedCol-FixItPos, ' ');
501        FixItPos = TabExpandedCol;
502
503        // Walk to the end of the word.
504        while (FixItPos < FixItInsertionLine.size() &&
505               FixItInsertionLine[FixItPos] != ' ')
506          ++FixItPos;
507      }
508    }
509  }
510
511  // If the source line is too long for our terminal, select only the
512  // "interesting" source region within that line.
513  if (Columns && SourceLine.size() > Columns)
514    SelectInterestingSourceRegion(SourceLine, CaretLine, FixItInsertionLine,
515                                  CaretEndColNo, Columns);
516
517  // Finally, remove any blank spaces from the end of CaretLine.
518  while (CaretLine[CaretLine.size()-1] == ' ')
519    CaretLine.erase(CaretLine.end()-1);
520
521  // Emit what we have computed.
522  OS << SourceLine << '\n';
523
524  if (DiagOpts->ShowColors)
525    OS.changeColor(caretColor, true);
526  OS << CaretLine << '\n';
527  if (DiagOpts->ShowColors)
528    OS.resetColor();
529
530  if (!FixItInsertionLine.empty()) {
531    if (DiagOpts->ShowColors)
532      // Print fixit line in color
533      OS.changeColor(fixitColor, false);
534    if (DiagOpts->ShowSourceRanges)
535      OS << ' ';
536    OS << FixItInsertionLine << '\n';
537    if (DiagOpts->ShowColors)
538      OS.resetColor();
539  }
540
541  if (DiagOpts->ShowParseableFixits) {
542
543    // We follow FixItRewriter's example in not (yet) handling
544    // fix-its in macros.
545    bool BadApples = false;
546    for (const FixItHint *Hint = Hints; Hint != Hints + NumHints; ++Hint) {
547      if (Hint->RemoveRange.isInvalid() ||
548          Hint->RemoveRange.getBegin().isMacroID() ||
549          Hint->RemoveRange.getEnd().isMacroID()) {
550        BadApples = true;
551        break;
552      }
553    }
554
555    if (!BadApples) {
556      for (const FixItHint *Hint = Hints; Hint != Hints + NumHints; ++Hint) {
557
558        SourceLocation B = Hint->RemoveRange.getBegin();
559        SourceLocation E = Hint->RemoveRange.getEnd();
560
561        std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(B);
562        std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(E);
563
564        // Adjust for token ranges.
565        if (Hint->RemoveRange.isTokenRange())
566          EInfo.second += Lexer::MeasureTokenLength(E, SM, *LangOpts);
567
568        // We specifically do not do word-wrapping or tab-expansion here,
569        // because this is supposed to be easy to parse.
570        OS << " fix-it: \"";
571        OS.write_escaped(SM.getPresumedLoc(B).getFilename());
572        OS << "\":{" << SM.getLineNumber(BInfo.first, BInfo.second)
573          << ':' << SM.getColumnNumber(BInfo.first, BInfo.second)
574          << '-' << SM.getLineNumber(EInfo.first, EInfo.second)
575          << ':' << SM.getColumnNumber(EInfo.first, EInfo.second)
576          << "}: \"";
577        OS.write_escaped(Hint->CodeToInsert);
578        OS << "\"\n";
579      }
580    }
581  }
582}
583
584/// \brief Skip over whitespace in the string, starting at the given
585/// index.
586///
587/// \returns The index of the first non-whitespace character that is
588/// greater than or equal to Idx or, if no such character exists,
589/// returns the end of the string.
590static unsigned skipWhitespace(unsigned Idx,
591                               const llvm::SmallVectorImpl<char> &Str,
592                               unsigned Length) {
593  while (Idx < Length && isspace(Str[Idx]))
594    ++Idx;
595  return Idx;
596}
597
598/// \brief If the given character is the start of some kind of
599/// balanced punctuation (e.g., quotes or parentheses), return the
600/// character that will terminate the punctuation.
601///
602/// \returns The ending punctuation character, if any, or the NULL
603/// character if the input character does not start any punctuation.
604static inline char findMatchingPunctuation(char c) {
605  switch (c) {
606  case '\'': return '\'';
607  case '`': return '\'';
608  case '"':  return '"';
609  case '(':  return ')';
610  case '[': return ']';
611  case '{': return '}';
612  default: break;
613  }
614
615  return 0;
616}
617
618/// \brief Find the end of the word starting at the given offset
619/// within a string.
620///
621/// \returns the index pointing one character past the end of the
622/// word.
623static unsigned findEndOfWord(unsigned Start,
624                              const llvm::SmallVectorImpl<char> &Str,
625                              unsigned Length, unsigned Column,
626                              unsigned Columns) {
627  assert(Start < Str.size() && "Invalid start position!");
628  unsigned End = Start + 1;
629
630  // If we are already at the end of the string, take that as the word.
631  if (End == Str.size())
632    return End;
633
634  // Determine if the start of the string is actually opening
635  // punctuation, e.g., a quote or parentheses.
636  char EndPunct = findMatchingPunctuation(Str[Start]);
637  if (!EndPunct) {
638    // This is a normal word. Just find the first space character.
639    while (End < Length && !isspace(Str[End]))
640      ++End;
641    return End;
642  }
643
644  // We have the start of a balanced punctuation sequence (quotes,
645  // parentheses, etc.). Determine the full sequence is.
646  llvm::SmallString<16> PunctuationEndStack;
647  PunctuationEndStack.push_back(EndPunct);
648  while (End < Length && !PunctuationEndStack.empty()) {
649    if (Str[End] == PunctuationEndStack.back())
650      PunctuationEndStack.pop_back();
651    else if (char SubEndPunct = findMatchingPunctuation(Str[End]))
652      PunctuationEndStack.push_back(SubEndPunct);
653
654    ++End;
655  }
656
657  // Find the first space character after the punctuation ended.
658  while (End < Length && !isspace(Str[End]))
659    ++End;
660
661  unsigned PunctWordLength = End - Start;
662  if (// If the word fits on this line
663      Column + PunctWordLength <= Columns ||
664      // ... or the word is "short enough" to take up the next line
665      // without too much ugly white space
666      PunctWordLength < Columns/3)
667    return End; // Take the whole thing as a single "word".
668
669  // The whole quoted/parenthesized string is too long to print as a
670  // single "word". Instead, find the "word" that starts just after
671  // the punctuation and use that end-point instead. This will recurse
672  // until it finds something small enough to consider a word.
673  return findEndOfWord(Start + 1, Str, Length, Column + 1, Columns);
674}
675
676/// \brief Print the given string to a stream, word-wrapping it to
677/// some number of columns in the process.
678///
679/// \brief OS the stream to which the word-wrapping string will be
680/// emitted.
681///
682/// \brief Str the string to word-wrap and output.
683///
684/// \brief Columns the number of columns to word-wrap to.
685///
686/// \brief Column the column number at which the first character of \p
687/// Str will be printed. This will be non-zero when part of the first
688/// line has already been printed.
689///
690/// \brief Indentation the number of spaces to indent any lines beyond
691/// the first line.
692///
693/// \returns true if word-wrapping was required, or false if the
694/// string fit on the first line.
695static bool PrintWordWrapped(llvm::raw_ostream &OS,
696                             const llvm::SmallVectorImpl<char> &Str,
697                             unsigned Columns,
698                             unsigned Column = 0,
699                             unsigned Indentation = WordWrapIndentation) {
700  unsigned Length = Str.size();
701
702  // If there is a newline in this message somewhere, find that
703  // newline and split the message into the part before the newline
704  // (which will be word-wrapped) and the part from the newline one
705  // (which will be emitted unchanged).
706  for (unsigned I = 0; I != Length; ++I)
707    if (Str[I] == '\n') {
708      Length = I;
709      break;
710    }
711
712  // The string used to indent each line.
713  llvm::SmallString<16> IndentStr;
714  IndentStr.assign(Indentation, ' ');
715  bool Wrapped = false;
716  for (unsigned WordStart = 0, WordEnd; WordStart < Length;
717       WordStart = WordEnd) {
718    // Find the beginning of the next word.
719    WordStart = skipWhitespace(WordStart, Str, Length);
720    if (WordStart == Length)
721      break;
722
723    // Find the end of this word.
724    WordEnd = findEndOfWord(WordStart, Str, Length, Column, Columns);
725
726    // Does this word fit on the current line?
727    unsigned WordLength = WordEnd - WordStart;
728    if (Column + WordLength < Columns) {
729      // This word fits on the current line; print it there.
730      if (WordStart) {
731        OS << ' ';
732        Column += 1;
733      }
734      OS.write(&Str[WordStart], WordLength);
735      Column += WordLength;
736      continue;
737    }
738
739    // This word does not fit on the current line, so wrap to the next
740    // line.
741    OS << '\n';
742    OS.write(&IndentStr[0], Indentation);
743    OS.write(&Str[WordStart], WordLength);
744    Column = Indentation + WordLength;
745    Wrapped = true;
746  }
747
748  if (Length == Str.size())
749    return Wrapped; // We're done.
750
751  // There is a newline in the message, followed by something that
752  // will not be word-wrapped. Print that.
753  OS.write(&Str[Length], Str.size() - Length);
754  return true;
755}
756
757void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
758                                             const DiagnosticInfo &Info) {
759  // Keeps track of the the starting position of the location
760  // information (e.g., "foo.c:10:4:") that precedes the error
761  // message. We use this information to determine how long the
762  // file+line+column number prefix is.
763  uint64_t StartOfLocationInfo = OS.tell();
764
765  if (!Prefix.empty())
766    OS << Prefix << ": ";
767
768  // If the location is specified, print out a file/line/col and include trace
769  // if enabled.
770  if (Info.getLocation().isValid()) {
771    const SourceManager &SM = Info.getLocation().getManager();
772    PresumedLoc PLoc = SM.getPresumedLoc(Info.getLocation());
773    unsigned LineNo = PLoc.getLine();
774
775    // First, if this diagnostic is not in the main file, print out the
776    // "included from" lines.
777    if (LastWarningLoc != PLoc.getIncludeLoc()) {
778      LastWarningLoc = PLoc.getIncludeLoc();
779      PrintIncludeStack(LastWarningLoc, SM);
780      StartOfLocationInfo = OS.tell();
781    }
782
783    // Compute the column number.
784    if (DiagOpts->ShowLocation) {
785      if (DiagOpts->ShowColors)
786        OS.changeColor(savedColor, true);
787
788      // Emit a Visual Studio compatible line number syntax.
789      if (LangOpts && LangOpts->Microsoft) {
790        OS << PLoc.getFilename() << '(' << LineNo << ')';
791        OS << " : ";
792      } else {
793        OS << PLoc.getFilename() << ':' << LineNo << ':';
794        if (DiagOpts->ShowColumn)
795          if (unsigned ColNo = PLoc.getColumn())
796            OS << ColNo << ':';
797      }
798      if (DiagOpts->ShowSourceRanges && Info.getNumRanges()) {
799        FileID CaretFileID =
800          SM.getFileID(SM.getInstantiationLoc(Info.getLocation()));
801        bool PrintedRange = false;
802
803        for (unsigned i = 0, e = Info.getNumRanges(); i != e; ++i) {
804          // Ignore invalid ranges.
805          if (!Info.getRange(i).isValid()) continue;
806
807          SourceLocation B = Info.getRange(i).getBegin();
808          SourceLocation E = Info.getRange(i).getEnd();
809          B = SM.getInstantiationLoc(B);
810          E = SM.getInstantiationLoc(E);
811
812          // If the End location and the start location are the same and are a
813          // macro location, then the range was something that came from a macro
814          // expansion or _Pragma.  If this is an object-like macro, the best we
815          // can do is to highlight the range.  If this is a function-like
816          // macro, we'd also like to highlight the arguments.
817          if (B == E && Info.getRange(i).getEnd().isMacroID())
818            E = SM.getInstantiationRange(Info.getRange(i).getEnd()).second;
819
820          std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(B);
821          std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(E);
822
823          // If the start or end of the range is in another file, just discard
824          // it.
825          if (BInfo.first != CaretFileID || EInfo.first != CaretFileID)
826            continue;
827
828          // Add in the length of the token, so that we cover multi-char tokens.
829          unsigned TokSize = 0;
830          if (Info.getRange(i).isTokenRange())
831            TokSize = Lexer::MeasureTokenLength(E, SM, *LangOpts);
832
833          OS << '{' << SM.getLineNumber(BInfo.first, BInfo.second) << ':'
834             << SM.getColumnNumber(BInfo.first, BInfo.second) << '-'
835             << SM.getLineNumber(EInfo.first, EInfo.second) << ':'
836             << (SM.getColumnNumber(EInfo.first, EInfo.second)+TokSize) << '}';
837          PrintedRange = true;
838        }
839
840        if (PrintedRange)
841          OS << ':';
842      }
843      OS << ' ';
844      if (DiagOpts->ShowColors)
845        OS.resetColor();
846    }
847  }
848
849  if (DiagOpts->ShowColors) {
850    // Print diagnostic category in bold and color
851    switch (Level) {
852    case Diagnostic::Ignored: assert(0 && "Invalid diagnostic type");
853    case Diagnostic::Note:    OS.changeColor(noteColor, true); break;
854    case Diagnostic::Warning: OS.changeColor(warningColor, true); break;
855    case Diagnostic::Error:   OS.changeColor(errorColor, true); break;
856    case Diagnostic::Fatal:   OS.changeColor(fatalColor, true); break;
857    }
858  }
859
860  switch (Level) {
861  case Diagnostic::Ignored: assert(0 && "Invalid diagnostic type");
862  case Diagnostic::Note:    OS << "note: "; break;
863  case Diagnostic::Warning: OS << "warning: "; break;
864  case Diagnostic::Error:   OS << "error: "; break;
865  case Diagnostic::Fatal:   OS << "fatal error: "; break;
866  }
867
868  if (DiagOpts->ShowColors)
869    OS.resetColor();
870
871  llvm::SmallString<100> OutStr;
872  Info.FormatDiagnostic(OutStr);
873
874  std::string OptionName;
875  if (DiagOpts->ShowOptionNames) {
876    if (const char *Opt = Diagnostic::getWarningOptionForDiag(Info.getID())) {
877      OptionName = "-W";
878      OptionName += Opt;
879    } else if (Info.getID() == diag::fatal_too_many_errors) {
880      OptionName = "-ferror-limit=";
881    } else {
882      // If the diagnostic is an extension diagnostic and not enabled by default
883      // then it must have been turned on with -pedantic.
884      bool EnabledByDefault;
885      if (Diagnostic::isBuiltinExtensionDiag(Info.getID(), EnabledByDefault) &&
886          !EnabledByDefault)
887        OptionName = "-pedantic";
888    }
889  }
890
891  // If the user wants to see category information, include it too.
892  unsigned DiagCategory = 0;
893  if (DiagOpts->ShowCategories)
894    DiagCategory = Diagnostic::getCategoryNumberForDiag(Info.getID());
895
896  // If there is any categorization information, include it.
897  if (!OptionName.empty() || DiagCategory != 0) {
898    bool NeedsComma = false;
899    OutStr += " [";
900
901    if (!OptionName.empty()) {
902      OutStr += OptionName;
903      NeedsComma = true;
904    }
905
906    if (DiagCategory) {
907      if (NeedsComma) OutStr += ',';
908      if (DiagOpts->ShowCategories == 1)
909        OutStr += llvm::utostr(DiagCategory);
910      else {
911        assert(DiagOpts->ShowCategories == 2 && "Invalid ShowCategories value");
912        OutStr += Diagnostic::getCategoryNameFromID(DiagCategory);
913      }
914    }
915
916    OutStr += "]";
917  }
918
919
920  if (DiagOpts->ShowColors) {
921    // Print warnings, errors and fatal errors in bold, no color
922    switch (Level) {
923    case Diagnostic::Warning: OS.changeColor(savedColor, true); break;
924    case Diagnostic::Error:   OS.changeColor(savedColor, true); break;
925    case Diagnostic::Fatal:   OS.changeColor(savedColor, true); break;
926    default: break; //don't bold notes
927    }
928  }
929
930  if (DiagOpts->MessageLength) {
931    // We will be word-wrapping the error message, so compute the
932    // column number where we currently are (after printing the
933    // location information).
934    unsigned Column = OS.tell() - StartOfLocationInfo;
935    PrintWordWrapped(OS, OutStr, DiagOpts->MessageLength, Column);
936  } else {
937    OS.write(OutStr.begin(), OutStr.size());
938  }
939  OS << '\n';
940  if (DiagOpts->ShowColors)
941    OS.resetColor();
942
943  // If caret diagnostics are enabled and we have location, we want to
944  // emit the caret.  However, we only do this if the location moved
945  // from the last diagnostic, if the last diagnostic was a note that
946  // was part of a different warning or error diagnostic, or if the
947  // diagnostic has ranges.  We don't want to emit the same caret
948  // multiple times if one loc has multiple diagnostics.
949  if (DiagOpts->ShowCarets && Info.getLocation().isValid() &&
950      ((LastLoc != Info.getLocation()) || Info.getNumRanges() ||
951       (LastCaretDiagnosticWasNote && Level != Diagnostic::Note) ||
952       Info.getNumFixItHints())) {
953    // Cache the LastLoc, it allows us to omit duplicate source/caret spewage.
954    LastLoc = Info.getLocation();
955    LastCaretDiagnosticWasNote = (Level == Diagnostic::Note);
956
957    // Get the ranges into a local array we can hack on.
958    CharSourceRange Ranges[20];
959    unsigned NumRanges = Info.getNumRanges();
960    assert(NumRanges < 20 && "Out of space");
961    for (unsigned i = 0; i != NumRanges; ++i)
962      Ranges[i] = Info.getRange(i);
963
964    unsigned NumHints = Info.getNumFixItHints();
965    for (unsigned i = 0; i != NumHints; ++i) {
966      const FixItHint &Hint = Info.getFixItHint(i);
967      if (Hint.RemoveRange.isValid()) {
968        assert(NumRanges < 20 && "Out of space");
969        Ranges[NumRanges++] = Hint.RemoveRange;
970      }
971    }
972
973    unsigned MacroInstSkipStart = 0, MacroInstSkipEnd = 0;
974    if (DiagOpts && DiagOpts->MacroBacktraceLimit && !LastLoc.isFileID()) {
975      // Compute the length of the macro-instantiation backtrace, so that we
976      // can establish which steps in the macro backtrace we'll skip.
977      SourceLocation Loc = LastLoc;
978      unsigned Depth = 0;
979      do {
980        ++Depth;
981        Loc = LastLoc.getManager().getImmediateInstantiationRange(Loc).first;
982      } while (!Loc.isFileID());
983
984      if (Depth > DiagOpts->MacroBacktraceLimit) {
985        MacroInstSkipStart = DiagOpts->MacroBacktraceLimit / 2 +
986                             DiagOpts->MacroBacktraceLimit % 2;
987        MacroInstSkipEnd = Depth - DiagOpts->MacroBacktraceLimit / 2;
988      }
989    }
990
991    EmitCaretDiagnostic(LastLoc, Ranges, NumRanges, LastLoc.getManager(),
992                        Info.getFixItHints(),
993                        Info.getNumFixItHints(),
994                        DiagOpts->MessageLength,
995                        0, MacroInstSkipStart, MacroInstSkipEnd);
996  }
997
998  OS.flush();
999}
1000