clang API Documentation
00001 //===--- TextDiagnosticPrinter.cpp - Diagnostic Printer -------------------===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This diagnostic client prints out their diagnostic messages. 00011 // 00012 //===----------------------------------------------------------------------===// 00013 00014 #include "clang/Frontend/TextDiagnosticPrinter.h" 00015 #include "clang/Basic/SourceManager.h" 00016 #include "clang/Frontend/DiagnosticOptions.h" 00017 #include "clang/Lex/Lexer.h" 00018 #include "llvm/Support/MemoryBuffer.h" 00019 #include "llvm/Support/raw_ostream.h" 00020 #include "llvm/ADT/SmallString.h" 00021 #include "llvm/ADT/StringExtras.h" 00022 #include <algorithm> 00023 using namespace clang; 00024 00025 static const enum llvm::raw_ostream::Colors noteColor = 00026 llvm::raw_ostream::BLACK; 00027 static const enum llvm::raw_ostream::Colors fixitColor = 00028 llvm::raw_ostream::GREEN; 00029 static const enum llvm::raw_ostream::Colors caretColor = 00030 llvm::raw_ostream::GREEN; 00031 static const enum llvm::raw_ostream::Colors warningColor = 00032 llvm::raw_ostream::MAGENTA; 00033 static const enum llvm::raw_ostream::Colors errorColor = llvm::raw_ostream::RED; 00034 static const enum llvm::raw_ostream::Colors fatalColor = llvm::raw_ostream::RED; 00035 // Used for changing only the bold attribute. 00036 static const enum llvm::raw_ostream::Colors savedColor = 00037 llvm::raw_ostream::SAVEDCOLOR; 00038 00039 /// \brief Number of spaces to indent when word-wrapping. 00040 const unsigned WordWrapIndentation = 6; 00041 00042 TextDiagnosticPrinter::TextDiagnosticPrinter(llvm::raw_ostream &os, 00043 const DiagnosticOptions &diags, 00044 bool _OwnsOutputStream) 00045 : OS(os), LangOpts(0), DiagOpts(&diags), 00046 LastCaretDiagnosticWasNote(0), 00047 OwnsOutputStream(_OwnsOutputStream) { 00048 } 00049 00050 TextDiagnosticPrinter::~TextDiagnosticPrinter() { 00051 if (OwnsOutputStream) 00052 delete &OS; 00053 } 00054 00055 void TextDiagnosticPrinter:: 00056 PrintIncludeStack(SourceLocation Loc, const SourceManager &SM) { 00057 if (Loc.isInvalid()) return; 00058 00059 PresumedLoc PLoc = SM.getPresumedLoc(Loc); 00060 00061 // Print out the other include frames first. 00062 PrintIncludeStack(PLoc.getIncludeLoc(), SM); 00063 00064 if (DiagOpts->ShowLocation) 00065 OS << "In file included from " << PLoc.getFilename() 00066 << ':' << PLoc.getLine() << ":\n"; 00067 else 00068 OS << "In included file:\n"; 00069 } 00070 00071 /// HighlightRange - Given a SourceRange and a line number, highlight (with ~'s) 00072 /// any characters in LineNo that intersect the SourceRange. 00073 void TextDiagnosticPrinter::HighlightRange(const SourceRange &R, 00074 const SourceManager &SM, 00075 unsigned LineNo, FileID FID, 00076 std::string &CaretLine, 00077 const std::string &SourceLine) { 00078 assert(CaretLine.size() == SourceLine.size() && 00079 "Expect a correspondence between source and caret line!"); 00080 if (!R.isValid()) return; 00081 00082 SourceLocation Begin = SM.getInstantiationLoc(R.getBegin()); 00083 SourceLocation End = SM.getInstantiationLoc(R.getEnd()); 00084 00085 // If the End location and the start location are the same and are a macro 00086 // location, then the range was something that came from a macro expansion 00087 // or _Pragma. If this is an object-like macro, the best we can do is to 00088 // highlight the range. If this is a function-like macro, we'd also like to 00089 // highlight the arguments. 00090 if (Begin == End && R.getEnd().isMacroID()) 00091 End = SM.getInstantiationRange(R.getEnd()).second; 00092 00093 unsigned StartLineNo = SM.getInstantiationLineNumber(Begin); 00094 if (StartLineNo > LineNo || SM.getFileID(Begin) != FID) 00095 return; // No intersection. 00096 00097 unsigned EndLineNo = SM.getInstantiationLineNumber(End); 00098 if (EndLineNo < LineNo || SM.getFileID(End) != FID) 00099 return; // No intersection. 00100 00101 // Compute the column number of the start. 00102 unsigned StartColNo = 0; 00103 if (StartLineNo == LineNo) { 00104 StartColNo = SM.getInstantiationColumnNumber(Begin); 00105 if (StartColNo) --StartColNo; // Zero base the col #. 00106 } 00107 00108 // Compute the column number of the end. 00109 unsigned EndColNo = CaretLine.size(); 00110 if (EndLineNo == LineNo) { 00111 EndColNo = SM.getInstantiationColumnNumber(End); 00112 if (EndColNo) { 00113 --EndColNo; // Zero base the col #. 00114 00115 // Add in the length of the token, so that we cover multi-char tokens. 00116 EndColNo += Lexer::MeasureTokenLength(End, SM, *LangOpts); 00117 } else { 00118 EndColNo = CaretLine.size(); 00119 } 00120 } 00121 00122 assert(StartColNo <= EndColNo && "Invalid range!"); 00123 00124 // Pick the first non-whitespace column. 00125 while (StartColNo < SourceLine.size() && 00126 (SourceLine[StartColNo] == ' ' || SourceLine[StartColNo] == '\t')) 00127 ++StartColNo; 00128 00129 // Pick the last non-whitespace column. 00130 if (EndColNo > SourceLine.size()) 00131 EndColNo = SourceLine.size(); 00132 while (EndColNo-1 && 00133 (SourceLine[EndColNo-1] == ' ' || SourceLine[EndColNo-1] == '\t')) 00134 --EndColNo; 00135 00136 // If the start/end passed each other, then we are trying to highlight a range 00137 // that just exists in whitespace, which must be some sort of other bug. 00138 assert(StartColNo <= EndColNo && "Trying to highlight whitespace??"); 00139 00140 // Fill the range with ~'s. 00141 for (unsigned i = StartColNo; i < EndColNo; ++i) 00142 CaretLine[i] = '~'; 00143 } 00144 00145 /// \brief When the source code line we want to print is too long for 00146 /// the terminal, select the "interesting" region. 00147 static void SelectInterestingSourceRegion(std::string &SourceLine, 00148 std::string &CaretLine, 00149 std::string &FixItInsertionLine, 00150 unsigned EndOfCaretToken, 00151 unsigned Columns) { 00152 unsigned MaxSize = std::max(SourceLine.size(), 00153 std::max(CaretLine.size(), 00154 FixItInsertionLine.size())); 00155 if (MaxSize > SourceLine.size()) 00156 SourceLine.resize(MaxSize, ' '); 00157 if (MaxSize > CaretLine.size()) 00158 CaretLine.resize(MaxSize, ' '); 00159 if (!FixItInsertionLine.empty() && MaxSize > FixItInsertionLine.size()) 00160 FixItInsertionLine.resize(MaxSize, ' '); 00161 00162 // Find the slice that we need to display the full caret line 00163 // correctly. 00164 unsigned CaretStart = 0, CaretEnd = CaretLine.size(); 00165 for (; CaretStart != CaretEnd; ++CaretStart) 00166 if (!isspace(CaretLine[CaretStart])) 00167 break; 00168 00169 for (; CaretEnd != CaretStart; --CaretEnd) 00170 if (!isspace(CaretLine[CaretEnd - 1])) 00171 break; 00172 00173 // Make sure we don't chop the string shorter than the caret token 00174 // itself. 00175 if (CaretEnd < EndOfCaretToken) 00176 CaretEnd = EndOfCaretToken; 00177 00178 // If we have a fix-it line, make sure the slice includes all of the 00179 // fix-it information. 00180 if (!FixItInsertionLine.empty()) { 00181 unsigned FixItStart = 0, FixItEnd = FixItInsertionLine.size(); 00182 for (; FixItStart != FixItEnd; ++FixItStart) 00183 if (!isspace(FixItInsertionLine[FixItStart])) 00184 break; 00185 00186 for (; FixItEnd != FixItStart; --FixItEnd) 00187 if (!isspace(FixItInsertionLine[FixItEnd - 1])) 00188 break; 00189 00190 if (FixItStart < CaretStart) 00191 CaretStart = FixItStart; 00192 if (FixItEnd > CaretEnd) 00193 CaretEnd = FixItEnd; 00194 } 00195 00196 // CaretLine[CaretStart, CaretEnd) contains all of the interesting 00197 // parts of the caret line. While this slice is smaller than the 00198 // number of columns we have, try to grow the slice to encompass 00199 // more context. 00200 00201 // If the end of the interesting region comes before we run out of 00202 // space in the terminal, start at the beginning of the line. 00203 if (Columns > 3 && CaretEnd < Columns - 3) 00204 CaretStart = 0; 00205 00206 unsigned TargetColumns = Columns; 00207 if (TargetColumns > 8) 00208 TargetColumns -= 8; // Give us extra room for the ellipses. 00209 unsigned SourceLength = SourceLine.size(); 00210 while ((CaretEnd - CaretStart) < TargetColumns) { 00211 bool ExpandedRegion = false; 00212 // Move the start of the interesting region left until we've 00213 // pulled in something else interesting. 00214 if (CaretStart == 1) 00215 CaretStart = 0; 00216 else if (CaretStart > 1) { 00217 unsigned NewStart = CaretStart - 1; 00218 00219 // Skip over any whitespace we see here; we're looking for 00220 // another bit of interesting text. 00221 while (NewStart && isspace(SourceLine[NewStart])) 00222 --NewStart; 00223 00224 // Skip over this bit of "interesting" text. 00225 while (NewStart && !isspace(SourceLine[NewStart])) 00226 --NewStart; 00227 00228 // Move up to the non-whitespace character we just saw. 00229 if (NewStart) 00230 ++NewStart; 00231 00232 // If we're still within our limit, update the starting 00233 // position within the source/caret line. 00234 if (CaretEnd - NewStart <= TargetColumns) { 00235 CaretStart = NewStart; 00236 ExpandedRegion = true; 00237 } 00238 } 00239 00240 // Move the end of the interesting region right until we've 00241 // pulled in something else interesting. 00242 if (CaretEnd != SourceLength) { 00243 assert(CaretEnd < SourceLength && "Unexpected caret position!"); 00244 unsigned NewEnd = CaretEnd; 00245 00246 // Skip over any whitespace we see here; we're looking for 00247 // another bit of interesting text. 00248 while (NewEnd != SourceLength && isspace(SourceLine[NewEnd - 1])) 00249 ++NewEnd; 00250 00251 // Skip over this bit of "interesting" text. 00252 while (NewEnd != SourceLength && !isspace(SourceLine[NewEnd - 1])) 00253 ++NewEnd; 00254 00255 if (NewEnd - CaretStart <= TargetColumns) { 00256 CaretEnd = NewEnd; 00257 ExpandedRegion = true; 00258 } 00259 } 00260 00261 if (!ExpandedRegion) 00262 break; 00263 } 00264 00265 // [CaretStart, CaretEnd) is the slice we want. Update the various 00266 // output lines to show only this slice, with two-space padding 00267 // before the lines so that it looks nicer. 00268 if (CaretEnd < SourceLine.size()) 00269 SourceLine.replace(CaretEnd, std::string::npos, "..."); 00270 if (CaretEnd < CaretLine.size()) 00271 CaretLine.erase(CaretEnd, std::string::npos); 00272 if (FixItInsertionLine.size() > CaretEnd) 00273 FixItInsertionLine.erase(CaretEnd, std::string::npos); 00274 00275 if (CaretStart > 2) { 00276 SourceLine.replace(0, CaretStart, " ..."); 00277 CaretLine.replace(0, CaretStart, " "); 00278 if (FixItInsertionLine.size() >= CaretStart) 00279 FixItInsertionLine.replace(0, CaretStart, " "); 00280 } 00281 } 00282 00283 void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc, 00284 SourceRange *Ranges, 00285 unsigned NumRanges, 00286 const SourceManager &SM, 00287 const FixItHint *Hints, 00288 unsigned NumHints, 00289 unsigned Columns, 00290 unsigned OnMacroInst, 00291 unsigned MacroSkipStart, 00292 unsigned MacroSkipEnd) { 00293 assert(LangOpts && "Unexpected diagnostic outside source file processing"); 00294 assert(!Loc.isInvalid() && "must have a valid source location here"); 00295 00296 // If this is a macro ID, first emit information about where this was 00297 // instantiated (recursively) then emit information about where the token was 00298 // spelled from. 00299 if (!Loc.isFileID()) { 00300 // Whether to suppress printing this macro instantiation. 00301 bool Suppressed 00302 = OnMacroInst >= MacroSkipStart && OnMacroInst < MacroSkipEnd; 00303 00304 00305 SourceLocation OneLevelUp = SM.getImmediateInstantiationRange(Loc).first; 00306 // FIXME: Map ranges? 00307 EmitCaretDiagnostic(OneLevelUp, Ranges, NumRanges, SM, 0, 0, Columns, 00308 OnMacroInst + 1, MacroSkipStart, MacroSkipEnd); 00309 00310 // Map the location. 00311 Loc = SM.getImmediateSpellingLoc(Loc); 00312 00313 // Map the ranges. 00314 for (unsigned i = 0; i != NumRanges; ++i) { 00315 SourceLocation S = Ranges[i].getBegin(), E = Ranges[i].getEnd(); 00316 if (S.isMacroID()) S = SM.getImmediateSpellingLoc(S); 00317 if (E.isMacroID()) E = SM.getImmediateSpellingLoc(E); 00318 Ranges[i] = SourceRange(S, E); 00319 } 00320 00321 if (!Suppressed) { 00322 // Get the pretty name, according to #line directives etc. 00323 PresumedLoc PLoc = SM.getPresumedLoc(Loc); 00324 00325 // If this diagnostic is not in the main file, print out the 00326 // "included from" lines. 00327 if (LastWarningLoc != PLoc.getIncludeLoc()) { 00328 LastWarningLoc = PLoc.getIncludeLoc(); 00329 PrintIncludeStack(LastWarningLoc, SM); 00330 } 00331 00332 if (DiagOpts->ShowLocation) { 00333 // Emit the file/line/column that this expansion came from. 00334 OS << PLoc.getFilename() << ':' << PLoc.getLine() << ':'; 00335 if (DiagOpts->ShowColumn) 00336 OS << PLoc.getColumn() << ':'; 00337 OS << ' '; 00338 } 00339 OS << "note: instantiated from:\n"; 00340 00341 EmitCaretDiagnostic(Loc, Ranges, NumRanges, SM, Hints, NumHints, Columns, 00342 OnMacroInst + 1, MacroSkipStart, MacroSkipEnd); 00343 return; 00344 } 00345 00346 if (OnMacroInst == MacroSkipStart) { 00347 // Tell the user that we've skipped contexts. 00348 OS << "note: (skipping " << (MacroSkipEnd - MacroSkipStart) 00349 << " contexts in backtrace; use -fmacro-backtrace-limit=0 to see " 00350 "all)\n"; 00351 } 00352 00353 return; 00354 } 00355 00356 // Decompose the location into a FID/Offset pair. 00357 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc); 00358 FileID FID = LocInfo.first; 00359 unsigned FileOffset = LocInfo.second; 00360 00361 // Get information about the buffer it points into. 00362 bool Invalid = false; 00363 const char *BufStart = SM.getBufferData(FID, &Invalid).data(); 00364 if (Invalid) 00365 return; 00366 00367 unsigned ColNo = SM.getColumnNumber(FID, FileOffset); 00368 unsigned CaretEndColNo 00369 = ColNo + Lexer::MeasureTokenLength(Loc, SM, *LangOpts); 00370 00371 // Rewind from the current position to the start of the line. 00372 const char *TokPtr = BufStart+FileOffset; 00373 const char *LineStart = TokPtr-ColNo+1; // Column # is 1-based. 00374 00375 00376 // Compute the line end. Scan forward from the error position to the end of 00377 // the line. 00378 const char *LineEnd = TokPtr; 00379 while (*LineEnd != '\n' && *LineEnd != '\r' && *LineEnd != '\0') 00380 ++LineEnd; 00381 00382 // FIXME: This shouldn't be necessary, but the CaretEndColNo can extend past 00383 // the source line length as currently being computed. See 00384 // test/Misc/message-length.c. 00385 CaretEndColNo = std::min(CaretEndColNo, unsigned(LineEnd - LineStart)); 00386 00387 // Copy the line of code into an std::string for ease of manipulation. 00388 std::string SourceLine(LineStart, LineEnd); 00389 00390 // Create a line for the caret that is filled with spaces that is the same 00391 // length as the line of source code. 00392 std::string CaretLine(LineEnd-LineStart, ' '); 00393 00394 // Highlight all of the characters covered by Ranges with ~ characters. 00395 if (NumRanges) { 00396 unsigned LineNo = SM.getLineNumber(FID, FileOffset); 00397 00398 for (unsigned i = 0, e = NumRanges; i != e; ++i) 00399 HighlightRange(Ranges[i], SM, LineNo, FID, CaretLine, SourceLine); 00400 } 00401 00402 // Next, insert the caret itself. 00403 if (ColNo-1 < CaretLine.size()) 00404 CaretLine[ColNo-1] = '^'; 00405 else 00406 CaretLine.push_back('^'); 00407 00408 // Scan the source line, looking for tabs. If we find any, manually expand 00409 // them to spaces and update the CaretLine to match. 00410 for (unsigned i = 0; i != SourceLine.size(); ++i) { 00411 if (SourceLine[i] != '\t') continue; 00412 00413 // Replace this tab with at least one space. 00414 SourceLine[i] = ' '; 00415 00416 // Compute the number of spaces we need to insert. 00417 unsigned TabStop = DiagOpts->TabStop; 00418 assert(0 < TabStop && TabStop <= DiagnosticOptions::MaxTabStop && 00419 "Invalid -ftabstop value"); 00420 unsigned NumSpaces = ((i+TabStop)/TabStop * TabStop) - (i+1); 00421 assert(NumSpaces < TabStop && "Invalid computation of space amt"); 00422 00423 // Insert spaces into the SourceLine. 00424 SourceLine.insert(i+1, NumSpaces, ' '); 00425 00426 // Insert spaces or ~'s into CaretLine. 00427 CaretLine.insert(i+1, NumSpaces, CaretLine[i] == '~' ? '~' : ' '); 00428 } 00429 00430 // If we are in -fdiagnostics-print-source-range-info mode, we are trying to 00431 // produce easily machine parsable output. Add a space before the source line 00432 // and the caret to make it trivial to tell the main diagnostic line from what 00433 // the user is intended to see. 00434 if (DiagOpts->ShowSourceRanges) { 00435 SourceLine = ' ' + SourceLine; 00436 CaretLine = ' ' + CaretLine; 00437 } 00438 00439 std::string FixItInsertionLine; 00440 if (NumHints && DiagOpts->ShowFixits) { 00441 for (const FixItHint *Hint = Hints, *LastHint = Hints + NumHints; 00442 Hint != LastHint; ++Hint) { 00443 if (Hint->InsertionLoc.isValid()) { 00444 // We have an insertion hint. Determine whether the inserted 00445 // code is on the same line as the caret. 00446 std::pair<FileID, unsigned> HintLocInfo 00447 = SM.getDecomposedInstantiationLoc(Hint->InsertionLoc); 00448 if (SM.getLineNumber(HintLocInfo.first, HintLocInfo.second) == 00449 SM.getLineNumber(FID, FileOffset)) { 00450 // Insert the new code into the line just below the code 00451 // that the user wrote. 00452 unsigned HintColNo 00453 = SM.getColumnNumber(HintLocInfo.first, HintLocInfo.second); 00454 unsigned LastColumnModified 00455 = HintColNo - 1 + Hint->CodeToInsert.size(); 00456 if (LastColumnModified > FixItInsertionLine.size()) 00457 FixItInsertionLine.resize(LastColumnModified, ' '); 00458 std::copy(Hint->CodeToInsert.begin(), Hint->CodeToInsert.end(), 00459 FixItInsertionLine.begin() + HintColNo - 1); 00460 } else { 00461 FixItInsertionLine.clear(); 00462 break; 00463 } 00464 } 00465 } 00466 // Now that we have the entire fixit line, expand the tabs in it. 00467 // Since we don't want to insert spaces in the middle of a word, 00468 // find each word and the column it should line up with and insert 00469 // spaces until they match. 00470 if (!FixItInsertionLine.empty()) { 00471 unsigned FixItPos = 0; 00472 unsigned LinePos = 0; 00473 unsigned TabExpandedCol = 0; 00474 unsigned LineLength = LineEnd - LineStart; 00475 00476 while (FixItPos < FixItInsertionLine.size() && LinePos < LineLength) { 00477 // Find the next word in the FixIt line. 00478 while (FixItPos < FixItInsertionLine.size() && 00479 FixItInsertionLine[FixItPos] == ' ') 00480 ++FixItPos; 00481 unsigned CharDistance = FixItPos - TabExpandedCol; 00482 00483 // Walk forward in the source line, keeping track of 00484 // the tab-expanded column. 00485 for (unsigned I = 0; I < CharDistance; ++I, ++LinePos) 00486 if (LinePos >= LineLength || LineStart[LinePos] != '\t') 00487 ++TabExpandedCol; 00488 else 00489 TabExpandedCol = 00490 (TabExpandedCol/DiagOpts->TabStop + 1) * DiagOpts->TabStop; 00491 00492 // Adjust the fixit line to match this column. 00493 FixItInsertionLine.insert(FixItPos, TabExpandedCol-FixItPos, ' '); 00494 FixItPos = TabExpandedCol; 00495 00496 // Walk to the end of the word. 00497 while (FixItPos < FixItInsertionLine.size() && 00498 FixItInsertionLine[FixItPos] != ' ') 00499 ++FixItPos; 00500 } 00501 } 00502 } 00503 00504 // If the source line is too long for our terminal, select only the 00505 // "interesting" source region within that line. 00506 if (Columns && SourceLine.size() > Columns) 00507 SelectInterestingSourceRegion(SourceLine, CaretLine, FixItInsertionLine, 00508 CaretEndColNo, Columns); 00509 00510 // Finally, remove any blank spaces from the end of CaretLine. 00511 while (CaretLine[CaretLine.size()-1] == ' ') 00512 CaretLine.erase(CaretLine.end()-1); 00513 00514 // Emit what we have computed. 00515 OS << SourceLine << '\n'; 00516 00517 if (DiagOpts->ShowColors) 00518 OS.changeColor(caretColor, true); 00519 OS << CaretLine << '\n'; 00520 if (DiagOpts->ShowColors) 00521 OS.resetColor(); 00522 00523 if (!FixItInsertionLine.empty()) { 00524 if (DiagOpts->ShowColors) 00525 // Print fixit line in color 00526 OS.changeColor(fixitColor, false); 00527 if (DiagOpts->ShowSourceRanges) 00528 OS << ' '; 00529 OS << FixItInsertionLine << '\n'; 00530 if (DiagOpts->ShowColors) 00531 OS.resetColor(); 00532 } 00533 } 00534 00535 /// \brief Skip over whitespace in the string, starting at the given 00536 /// index. 00537 /// 00538 /// \returns The index of the first non-whitespace character that is 00539 /// greater than or equal to Idx or, if no such character exists, 00540 /// returns the end of the string. 00541 static unsigned skipWhitespace(unsigned Idx, 00542 const llvm::SmallVectorImpl<char> &Str, 00543 unsigned Length) { 00544 while (Idx < Length && isspace(Str[Idx])) 00545 ++Idx; 00546 return Idx; 00547 } 00548 00549 /// \brief If the given character is the start of some kind of 00550 /// balanced punctuation (e.g., quotes or parentheses), return the 00551 /// character that will terminate the punctuation. 00552 /// 00553 /// \returns The ending punctuation character, if any, or the NULL 00554 /// character if the input character does not start any punctuation. 00555 static inline char findMatchingPunctuation(char c) { 00556 switch (c) { 00557 case '\'': return '\''; 00558 case '`': return '\''; 00559 case '"': return '"'; 00560 case '(': return ')'; 00561 case '[': return ']'; 00562 case '{': return '}'; 00563 default: break; 00564 } 00565 00566 return 0; 00567 } 00568 00569 /// \brief Find the end of the word starting at the given offset 00570 /// within a string. 00571 /// 00572 /// \returns the index pointing one character past the end of the 00573 /// word. 00574 static unsigned findEndOfWord(unsigned Start, 00575 const llvm::SmallVectorImpl<char> &Str, 00576 unsigned Length, unsigned Column, 00577 unsigned Columns) { 00578 assert(Start < Str.size() && "Invalid start position!"); 00579 unsigned End = Start + 1; 00580 00581 // If we are already at the end of the string, take that as the word. 00582 if (End == Str.size()) 00583 return End; 00584 00585 // Determine if the start of the string is actually opening 00586 // punctuation, e.g., a quote or parentheses. 00587 char EndPunct = findMatchingPunctuation(Str[Start]); 00588 if (!EndPunct) { 00589 // This is a normal word. Just find the first space character. 00590 while (End < Length && !isspace(Str[End])) 00591 ++End; 00592 return End; 00593 } 00594 00595 // We have the start of a balanced punctuation sequence (quotes, 00596 // parentheses, etc.). Determine the full sequence is. 00597 llvm::SmallString<16> PunctuationEndStack; 00598 PunctuationEndStack.push_back(EndPunct); 00599 while (End < Length && !PunctuationEndStack.empty()) { 00600 if (Str[End] == PunctuationEndStack.back()) 00601 PunctuationEndStack.pop_back(); 00602 else if (char SubEndPunct = findMatchingPunctuation(Str[End])) 00603 PunctuationEndStack.push_back(SubEndPunct); 00604 00605 ++End; 00606 } 00607 00608 // Find the first space character after the punctuation ended. 00609 while (End < Length && !isspace(Str[End])) 00610 ++End; 00611 00612 unsigned PunctWordLength = End - Start; 00613 if (// If the word fits on this line 00614 Column + PunctWordLength <= Columns || 00615 // ... or the word is "short enough" to take up the next line 00616 // without too much ugly white space 00617 PunctWordLength < Columns/3) 00618 return End; // Take the whole thing as a single "word". 00619 00620 // The whole quoted/parenthesized string is too long to print as a 00621 // single "word". Instead, find the "word" that starts just after 00622 // the punctuation and use that end-point instead. This will recurse 00623 // until it finds something small enough to consider a word. 00624 return findEndOfWord(Start + 1, Str, Length, Column + 1, Columns); 00625 } 00626 00627 /// \brief Print the given string to a stream, word-wrapping it to 00628 /// some number of columns in the process. 00629 /// 00630 /// \brief OS the stream to which the word-wrapping string will be 00631 /// emitted. 00632 /// 00633 /// \brief Str the string to word-wrap and output. 00634 /// 00635 /// \brief Columns the number of columns to word-wrap to. 00636 /// 00637 /// \brief Column the column number at which the first character of \p 00638 /// Str will be printed. This will be non-zero when part of the first 00639 /// line has already been printed. 00640 /// 00641 /// \brief Indentation the number of spaces to indent any lines beyond 00642 /// the first line. 00643 /// 00644 /// \returns true if word-wrapping was required, or false if the 00645 /// string fit on the first line. 00646 static bool PrintWordWrapped(llvm::raw_ostream &OS, 00647 const llvm::SmallVectorImpl<char> &Str, 00648 unsigned Columns, 00649 unsigned Column = 0, 00650 unsigned Indentation = WordWrapIndentation) { 00651 unsigned Length = Str.size(); 00652 00653 // If there is a newline in this message somewhere, find that 00654 // newline and split the message into the part before the newline 00655 // (which will be word-wrapped) and the part from the newline one 00656 // (which will be emitted unchanged). 00657 for (unsigned I = 0; I != Length; ++I) 00658 if (Str[I] == '\n') { 00659 Length = I; 00660 break; 00661 } 00662 00663 // The string used to indent each line. 00664 llvm::SmallString<16> IndentStr; 00665 IndentStr.assign(Indentation, ' '); 00666 bool Wrapped = false; 00667 for (unsigned WordStart = 0, WordEnd; WordStart < Length; 00668 WordStart = WordEnd) { 00669 // Find the beginning of the next word. 00670 WordStart = skipWhitespace(WordStart, Str, Length); 00671 if (WordStart == Length) 00672 break; 00673 00674 // Find the end of this word. 00675 WordEnd = findEndOfWord(WordStart, Str, Length, Column, Columns); 00676 00677 // Does this word fit on the current line? 00678 unsigned WordLength = WordEnd - WordStart; 00679 if (Column + WordLength < Columns) { 00680 // This word fits on the current line; print it there. 00681 if (WordStart) { 00682 OS << ' '; 00683 Column += 1; 00684 } 00685 OS.write(&Str[WordStart], WordLength); 00686 Column += WordLength; 00687 continue; 00688 } 00689 00690 // This word does not fit on the current line, so wrap to the next 00691 // line. 00692 OS << '\n'; 00693 OS.write(&IndentStr[0], Indentation); 00694 OS.write(&Str[WordStart], WordLength); 00695 Column = Indentation + WordLength; 00696 Wrapped = true; 00697 } 00698 00699 if (Length == Str.size()) 00700 return Wrapped; // We're done. 00701 00702 // There is a newline in the message, followed by something that 00703 // will not be word-wrapped. Print that. 00704 OS.write(&Str[Length], Str.size() - Length); 00705 return true; 00706 } 00707 00708 void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, 00709 const DiagnosticInfo &Info) { 00710 // Keeps track of the the starting position of the location 00711 // information (e.g., "foo.c:10:4:") that precedes the error 00712 // message. We use this information to determine how long the 00713 // file+line+column number prefix is. 00714 uint64_t StartOfLocationInfo = OS.tell(); 00715 00716 if (!Prefix.empty()) 00717 OS << Prefix << ": "; 00718 00719 // If the location is specified, print out a file/line/col and include trace 00720 // if enabled. 00721 if (Info.getLocation().isValid()) { 00722 const SourceManager &SM = Info.getLocation().getManager(); 00723 PresumedLoc PLoc = SM.getPresumedLoc(Info.getLocation()); 00724 unsigned LineNo = PLoc.getLine(); 00725 00726 // First, if this diagnostic is not in the main file, print out the 00727 // "included from" lines. 00728 if (LastWarningLoc != PLoc.getIncludeLoc()) { 00729 LastWarningLoc = PLoc.getIncludeLoc(); 00730 PrintIncludeStack(LastWarningLoc, SM); 00731 StartOfLocationInfo = OS.tell(); 00732 } 00733 00734 // Compute the column number. 00735 if (DiagOpts->ShowLocation) { 00736 if (DiagOpts->ShowColors) 00737 OS.changeColor(savedColor, true); 00738 00739 // Emit a Visual Studio compatible line number syntax. 00740 if (LangOpts && LangOpts->Microsoft) { 00741 OS << PLoc.getFilename() << '(' << LineNo << ')'; 00742 OS << " : "; 00743 } else { 00744 OS << PLoc.getFilename() << ':' << LineNo << ':'; 00745 if (DiagOpts->ShowColumn) 00746 if (unsigned ColNo = PLoc.getColumn()) 00747 OS << ColNo << ':'; 00748 } 00749 if (DiagOpts->ShowSourceRanges && Info.getNumRanges()) { 00750 FileID CaretFileID = 00751 SM.getFileID(SM.getInstantiationLoc(Info.getLocation())); 00752 bool PrintedRange = false; 00753 00754 for (unsigned i = 0, e = Info.getNumRanges(); i != e; ++i) { 00755 // Ignore invalid ranges. 00756 if (!Info.getRange(i).isValid()) continue; 00757 00758 SourceLocation B = Info.getRange(i).getBegin(); 00759 SourceLocation E = Info.getRange(i).getEnd(); 00760 B = SM.getInstantiationLoc(B); 00761 E = SM.getInstantiationLoc(E); 00762 00763 // If the End location and the start location are the same and are a 00764 // macro location, then the range was something that came from a macro 00765 // expansion or _Pragma. If this is an object-like macro, the best we 00766 // can do is to highlight the range. If this is a function-like 00767 // macro, we'd also like to highlight the arguments. 00768 if (B == E && Info.getRange(i).getEnd().isMacroID()) 00769 E = SM.getInstantiationRange(Info.getRange(i).getEnd()).second; 00770 00771 std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(B); 00772 std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(E); 00773 00774 // If the start or end of the range is in another file, just discard 00775 // it. 00776 if (BInfo.first != CaretFileID || EInfo.first != CaretFileID) 00777 continue; 00778 00779 // Add in the length of the token, so that we cover multi-char tokens. 00780 unsigned TokSize = Lexer::MeasureTokenLength(E, SM, *LangOpts); 00781 00782 OS << '{' << SM.getLineNumber(BInfo.first, BInfo.second) << ':' 00783 << SM.getColumnNumber(BInfo.first, BInfo.second) << '-' 00784 << SM.getLineNumber(EInfo.first, EInfo.second) << ':' 00785 << (SM.getColumnNumber(EInfo.first, EInfo.second)+TokSize) << '}'; 00786 PrintedRange = true; 00787 } 00788 00789 if (PrintedRange) 00790 OS << ':'; 00791 } 00792 OS << ' '; 00793 if (DiagOpts->ShowColors) 00794 OS.resetColor(); 00795 } 00796 } 00797 00798 if (DiagOpts->ShowColors) { 00799 // Print diagnostic category in bold and color 00800 switch (Level) { 00801 case Diagnostic::Ignored: assert(0 && "Invalid diagnostic type"); 00802 case Diagnostic::Note: OS.changeColor(noteColor, true); break; 00803 case Diagnostic::Warning: OS.changeColor(warningColor, true); break; 00804 case Diagnostic::Error: OS.changeColor(errorColor, true); break; 00805 case Diagnostic::Fatal: OS.changeColor(fatalColor, true); break; 00806 } 00807 } 00808 00809 switch (Level) { 00810 case Diagnostic::Ignored: assert(0 && "Invalid diagnostic type"); 00811 case Diagnostic::Note: OS << "note: "; break; 00812 case Diagnostic::Warning: OS << "warning: "; break; 00813 case Diagnostic::Error: OS << "error: "; break; 00814 case Diagnostic::Fatal: OS << "fatal error: "; break; 00815 } 00816 00817 if (DiagOpts->ShowColors) 00818 OS.resetColor(); 00819 00820 llvm::SmallString<100> OutStr; 00821 Info.FormatDiagnostic(OutStr); 00822 00823 std::string OptionName; 00824 if (DiagOpts->ShowOptionNames) { 00825 if (const char *Opt = Diagnostic::getWarningOptionForDiag(Info.getID())) { 00826 OptionName = "-W"; 00827 OptionName += Opt; 00828 } else { 00829 // If the diagnostic is an extension diagnostic and not enabled by default 00830 // then it must have been turned on with -pedantic. 00831 bool EnabledByDefault; 00832 if (Diagnostic::isBuiltinExtensionDiag(Info.getID(), EnabledByDefault) && 00833 !EnabledByDefault) 00834 OptionName = "-pedantic"; 00835 } 00836 } 00837 00838 // If the user wants to see category information, include it too. 00839 unsigned DiagCategory = 0; 00840 if (DiagOpts->ShowCategories) 00841 DiagCategory = Diagnostic::getCategoryNumberForDiag(Info.getID()); 00842 00843 // If there is any categorization information, include it. 00844 if (!OptionName.empty() || DiagCategory != 0) { 00845 bool NeedsComma = false; 00846 OutStr += " ["; 00847 00848 if (!OptionName.empty()) { 00849 OutStr += OptionName; 00850 NeedsComma = true; 00851 } 00852 00853 if (DiagCategory) { 00854 if (NeedsComma) OutStr += ','; 00855 if (DiagOpts->ShowCategories == 1) 00856 OutStr += llvm::utostr(DiagCategory); 00857 else { 00858 assert(DiagOpts->ShowCategories == 2 && "Invalid ShowCategories value"); 00859 OutStr += Diagnostic::getCategoryNameFromID(DiagCategory); 00860 } 00861 } 00862 00863 OutStr += "]"; 00864 } 00865 00866 00867 if (DiagOpts->ShowColors) { 00868 // Print warnings, errors and fatal errors in bold, no color 00869 switch (Level) { 00870 case Diagnostic::Warning: OS.changeColor(savedColor, true); break; 00871 case Diagnostic::Error: OS.changeColor(savedColor, true); break; 00872 case Diagnostic::Fatal: OS.changeColor(savedColor, true); break; 00873 default: break; //don't bold notes 00874 } 00875 } 00876 00877 if (DiagOpts->MessageLength) { 00878 // We will be word-wrapping the error message, so compute the 00879 // column number where we currently are (after printing the 00880 // location information). 00881 unsigned Column = OS.tell() - StartOfLocationInfo; 00882 PrintWordWrapped(OS, OutStr, DiagOpts->MessageLength, Column); 00883 } else { 00884 OS.write(OutStr.begin(), OutStr.size()); 00885 } 00886 OS << '\n'; 00887 if (DiagOpts->ShowColors) 00888 OS.resetColor(); 00889 00890 // If caret diagnostics are enabled and we have location, we want to 00891 // emit the caret. However, we only do this if the location moved 00892 // from the last diagnostic, if the last diagnostic was a note that 00893 // was part of a different warning or error diagnostic, or if the 00894 // diagnostic has ranges. We don't want to emit the same caret 00895 // multiple times if one loc has multiple diagnostics. 00896 if (DiagOpts->ShowCarets && Info.getLocation().isValid() && 00897 ((LastLoc != Info.getLocation()) || Info.getNumRanges() || 00898 (LastCaretDiagnosticWasNote && Level != Diagnostic::Note) || 00899 Info.getNumFixItHints())) { 00900 // Cache the LastLoc, it allows us to omit duplicate source/caret spewage. 00901 LastLoc = Info.getLocation(); 00902 LastCaretDiagnosticWasNote = (Level == Diagnostic::Note); 00903 00904 // Get the ranges into a local array we can hack on. 00905 SourceRange Ranges[20]; 00906 unsigned NumRanges = Info.getNumRanges(); 00907 assert(NumRanges < 20 && "Out of space"); 00908 for (unsigned i = 0; i != NumRanges; ++i) 00909 Ranges[i] = Info.getRange(i); 00910 00911 unsigned NumHints = Info.getNumFixItHints(); 00912 for (unsigned idx = 0; idx < NumHints; ++idx) { 00913 const FixItHint &Hint = Info.getFixItHint(idx); 00914 if (Hint.RemoveRange.isValid()) { 00915 assert(NumRanges < 20 && "Out of space"); 00916 Ranges[NumRanges++] = Hint.RemoveRange; 00917 } 00918 } 00919 00920 unsigned MacroInstSkipStart = 0, MacroInstSkipEnd = 0; 00921 if (DiagOpts && DiagOpts->MacroBacktraceLimit && !LastLoc.isFileID()) { 00922 // Compute the length of the macro-instantiation backtrace, so that we 00923 // can establish which steps in the macro backtrace we'll skip. 00924 SourceLocation Loc = LastLoc; 00925 unsigned Depth = 0; 00926 do { 00927 ++Depth; 00928 Loc = LastLoc.getManager().getImmediateInstantiationRange(Loc).first; 00929 } while (!Loc.isFileID()); 00930 00931 if (Depth > DiagOpts->MacroBacktraceLimit) { 00932 MacroInstSkipStart = DiagOpts->MacroBacktraceLimit / 2 + 00933 DiagOpts->MacroBacktraceLimit % 2; 00934 MacroInstSkipEnd = Depth - DiagOpts->MacroBacktraceLimit / 2; 00935 } 00936 } 00937 00938 EmitCaretDiagnostic(LastLoc, Ranges, NumRanges, LastLoc.getManager(), 00939 Info.getFixItHints(), 00940 Info.getNumFixItHints(), 00941 DiagOpts->MessageLength, 00942 0, MacroInstSkipStart, MacroInstSkipEnd); 00943 } 00944 00945 OS.flush(); 00946 }