LLVM API Documentation
00001 //===- SourceMgr.cpp - Manager for Simple Source Buffers & Diagnostics ----===// 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 file implements the SourceMgr class. This class is used as a simple 00011 // substrate for diagnostics, #include handling, and other low level things for 00012 // simple parsers. 00013 // 00014 //===----------------------------------------------------------------------===// 00015 00016 #include "llvm/Support/SourceMgr.h" 00017 #include "llvm/ADT/SmallString.h" 00018 #include "llvm/ADT/Twine.h" 00019 #include "llvm/Support/Locale.h" 00020 #include "llvm/Support/MemoryBuffer.h" 00021 #include "llvm/Support/Path.h" 00022 #include "llvm/Support/raw_ostream.h" 00023 #include <system_error> 00024 using namespace llvm; 00025 00026 static const size_t TabStop = 8; 00027 00028 namespace { 00029 struct LineNoCacheTy { 00030 unsigned LastQueryBufferID; 00031 const char *LastQuery; 00032 unsigned LineNoOfQuery; 00033 }; 00034 } 00035 00036 static LineNoCacheTy *getCache(void *Ptr) { 00037 return (LineNoCacheTy*)Ptr; 00038 } 00039 00040 00041 SourceMgr::~SourceMgr() { 00042 // Delete the line # cache if allocated. 00043 if (LineNoCacheTy *Cache = getCache(LineNoCache)) 00044 delete Cache; 00045 } 00046 00047 unsigned SourceMgr::AddIncludeFile(const std::string &Filename, 00048 SMLoc IncludeLoc, 00049 std::string &IncludedFile) { 00050 IncludedFile = Filename; 00051 ErrorOr<std::unique_ptr<MemoryBuffer>> NewBufOrErr = 00052 MemoryBuffer::getFile(IncludedFile.c_str()); 00053 00054 // If the file didn't exist directly, see if it's in an include path. 00055 for (unsigned i = 0, e = IncludeDirectories.size(); i != e && !NewBufOrErr; 00056 ++i) { 00057 IncludedFile = 00058 IncludeDirectories[i] + sys::path::get_separator().data() + Filename; 00059 NewBufOrErr = MemoryBuffer::getFile(IncludedFile.c_str()); 00060 } 00061 00062 if (!NewBufOrErr) 00063 return 0; 00064 00065 return AddNewSourceBuffer(std::move(*NewBufOrErr), IncludeLoc); 00066 } 00067 00068 unsigned SourceMgr::FindBufferContainingLoc(SMLoc Loc) const { 00069 for (unsigned i = 0, e = Buffers.size(); i != e; ++i) 00070 if (Loc.getPointer() >= Buffers[i].Buffer->getBufferStart() && 00071 // Use <= here so that a pointer to the null at the end of the buffer 00072 // is included as part of the buffer. 00073 Loc.getPointer() <= Buffers[i].Buffer->getBufferEnd()) 00074 return i + 1; 00075 return 0; 00076 } 00077 00078 std::pair<unsigned, unsigned> 00079 SourceMgr::getLineAndColumn(SMLoc Loc, unsigned BufferID) const { 00080 if (!BufferID) 00081 BufferID = FindBufferContainingLoc(Loc); 00082 assert(BufferID && "Invalid Location!"); 00083 00084 const MemoryBuffer *Buff = getMemoryBuffer(BufferID); 00085 00086 // Count the number of \n's between the start of the file and the specified 00087 // location. 00088 unsigned LineNo = 1; 00089 00090 const char *BufStart = Buff->getBufferStart(); 00091 const char *Ptr = BufStart; 00092 00093 // If we have a line number cache, and if the query is to a later point in the 00094 // same file, start searching from the last query location. This optimizes 00095 // for the case when multiple diagnostics come out of one file in order. 00096 if (LineNoCacheTy *Cache = getCache(LineNoCache)) 00097 if (Cache->LastQueryBufferID == BufferID && 00098 Cache->LastQuery <= Loc.getPointer()) { 00099 Ptr = Cache->LastQuery; 00100 LineNo = Cache->LineNoOfQuery; 00101 } 00102 00103 // Scan for the location being queried, keeping track of the number of lines 00104 // we see. 00105 for (; SMLoc::getFromPointer(Ptr) != Loc; ++Ptr) 00106 if (*Ptr == '\n') ++LineNo; 00107 00108 // Allocate the line number cache if it doesn't exist. 00109 if (!LineNoCache) 00110 LineNoCache = new LineNoCacheTy(); 00111 00112 // Update the line # cache. 00113 LineNoCacheTy &Cache = *getCache(LineNoCache); 00114 Cache.LastQueryBufferID = BufferID; 00115 Cache.LastQuery = Ptr; 00116 Cache.LineNoOfQuery = LineNo; 00117 00118 size_t NewlineOffs = StringRef(BufStart, Ptr-BufStart).find_last_of("\n\r"); 00119 if (NewlineOffs == StringRef::npos) NewlineOffs = ~(size_t)0; 00120 return std::make_pair(LineNo, Ptr-BufStart-NewlineOffs); 00121 } 00122 00123 void SourceMgr::PrintIncludeStack(SMLoc IncludeLoc, raw_ostream &OS) const { 00124 if (IncludeLoc == SMLoc()) return; // Top of stack. 00125 00126 unsigned CurBuf = FindBufferContainingLoc(IncludeLoc); 00127 assert(CurBuf && "Invalid or unspecified location!"); 00128 00129 PrintIncludeStack(getBufferInfo(CurBuf).IncludeLoc, OS); 00130 00131 OS << "Included from " 00132 << getBufferInfo(CurBuf).Buffer->getBufferIdentifier() 00133 << ":" << FindLineNumber(IncludeLoc, CurBuf) << ":\n"; 00134 } 00135 00136 00137 SMDiagnostic SourceMgr::GetMessage(SMLoc Loc, SourceMgr::DiagKind Kind, 00138 const Twine &Msg, 00139 ArrayRef<SMRange> Ranges, 00140 ArrayRef<SMFixIt> FixIts) const { 00141 00142 // First thing to do: find the current buffer containing the specified 00143 // location to pull out the source line. 00144 SmallVector<std::pair<unsigned, unsigned>, 4> ColRanges; 00145 std::pair<unsigned, unsigned> LineAndCol; 00146 const char *BufferID = "<unknown>"; 00147 std::string LineStr; 00148 00149 if (Loc.isValid()) { 00150 unsigned CurBuf = FindBufferContainingLoc(Loc); 00151 assert(CurBuf && "Invalid or unspecified location!"); 00152 00153 const MemoryBuffer *CurMB = getMemoryBuffer(CurBuf); 00154 BufferID = CurMB->getBufferIdentifier(); 00155 00156 // Scan backward to find the start of the line. 00157 const char *LineStart = Loc.getPointer(); 00158 const char *BufStart = CurMB->getBufferStart(); 00159 while (LineStart != BufStart && LineStart[-1] != '\n' && 00160 LineStart[-1] != '\r') 00161 --LineStart; 00162 00163 // Get the end of the line. 00164 const char *LineEnd = Loc.getPointer(); 00165 const char *BufEnd = CurMB->getBufferEnd(); 00166 while (LineEnd != BufEnd && LineEnd[0] != '\n' && LineEnd[0] != '\r') 00167 ++LineEnd; 00168 LineStr = std::string(LineStart, LineEnd); 00169 00170 // Convert any ranges to column ranges that only intersect the line of the 00171 // location. 00172 for (unsigned i = 0, e = Ranges.size(); i != e; ++i) { 00173 SMRange R = Ranges[i]; 00174 if (!R.isValid()) continue; 00175 00176 // If the line doesn't contain any part of the range, then ignore it. 00177 if (R.Start.getPointer() > LineEnd || R.End.getPointer() < LineStart) 00178 continue; 00179 00180 // Ignore pieces of the range that go onto other lines. 00181 if (R.Start.getPointer() < LineStart) 00182 R.Start = SMLoc::getFromPointer(LineStart); 00183 if (R.End.getPointer() > LineEnd) 00184 R.End = SMLoc::getFromPointer(LineEnd); 00185 00186 // Translate from SMLoc ranges to column ranges. 00187 // FIXME: Handle multibyte characters. 00188 ColRanges.push_back(std::make_pair(R.Start.getPointer()-LineStart, 00189 R.End.getPointer()-LineStart)); 00190 } 00191 00192 LineAndCol = getLineAndColumn(Loc, CurBuf); 00193 } 00194 00195 return SMDiagnostic(*this, Loc, BufferID, LineAndCol.first, 00196 LineAndCol.second-1, Kind, Msg.str(), 00197 LineStr, ColRanges, FixIts); 00198 } 00199 00200 void SourceMgr::PrintMessage(raw_ostream &OS, const SMDiagnostic &Diagnostic, 00201 bool ShowColors) const { 00202 // Report the message with the diagnostic handler if present. 00203 if (DiagHandler) { 00204 DiagHandler(Diagnostic, DiagContext); 00205 return; 00206 } 00207 00208 if (Diagnostic.getLoc().isValid()) { 00209 unsigned CurBuf = FindBufferContainingLoc(Diagnostic.getLoc()); 00210 assert(CurBuf && "Invalid or unspecified location!"); 00211 PrintIncludeStack(getBufferInfo(CurBuf).IncludeLoc, OS); 00212 } 00213 00214 Diagnostic.print(nullptr, OS, ShowColors); 00215 } 00216 00217 void SourceMgr::PrintMessage(raw_ostream &OS, SMLoc Loc, 00218 SourceMgr::DiagKind Kind, 00219 const Twine &Msg, ArrayRef<SMRange> Ranges, 00220 ArrayRef<SMFixIt> FixIts, bool ShowColors) const { 00221 PrintMessage(OS, GetMessage(Loc, Kind, Msg, Ranges, FixIts), ShowColors); 00222 } 00223 00224 void SourceMgr::PrintMessage(SMLoc Loc, SourceMgr::DiagKind Kind, 00225 const Twine &Msg, ArrayRef<SMRange> Ranges, 00226 ArrayRef<SMFixIt> FixIts, bool ShowColors) const { 00227 PrintMessage(llvm::errs(), Loc, Kind, Msg, Ranges, FixIts, ShowColors); 00228 } 00229 00230 //===----------------------------------------------------------------------===// 00231 // SMDiagnostic Implementation 00232 //===----------------------------------------------------------------------===// 00233 00234 SMDiagnostic::SMDiagnostic(const SourceMgr &sm, SMLoc L, StringRef FN, 00235 int Line, int Col, SourceMgr::DiagKind Kind, 00236 StringRef Msg, StringRef LineStr, 00237 ArrayRef<std::pair<unsigned,unsigned> > Ranges, 00238 ArrayRef<SMFixIt> Hints) 00239 : SM(&sm), Loc(L), Filename(FN), LineNo(Line), ColumnNo(Col), Kind(Kind), 00240 Message(Msg), LineContents(LineStr), Ranges(Ranges.vec()), 00241 FixIts(Hints.begin(), Hints.end()) { 00242 std::sort(FixIts.begin(), FixIts.end()); 00243 } 00244 00245 static void buildFixItLine(std::string &CaretLine, std::string &FixItLine, 00246 ArrayRef<SMFixIt> FixIts, ArrayRef<char> SourceLine){ 00247 if (FixIts.empty()) 00248 return; 00249 00250 const char *LineStart = SourceLine.begin(); 00251 const char *LineEnd = SourceLine.end(); 00252 00253 size_t PrevHintEndCol = 0; 00254 00255 for (ArrayRef<SMFixIt>::iterator I = FixIts.begin(), E = FixIts.end(); 00256 I != E; ++I) { 00257 // If the fixit contains a newline or tab, ignore it. 00258 if (I->getText().find_first_of("\n\r\t") != StringRef::npos) 00259 continue; 00260 00261 SMRange R = I->getRange(); 00262 00263 // If the line doesn't contain any part of the range, then ignore it. 00264 if (R.Start.getPointer() > LineEnd || R.End.getPointer() < LineStart) 00265 continue; 00266 00267 // Translate from SMLoc to column. 00268 // Ignore pieces of the range that go onto other lines. 00269 // FIXME: Handle multibyte characters in the source line. 00270 unsigned FirstCol; 00271 if (R.Start.getPointer() < LineStart) 00272 FirstCol = 0; 00273 else 00274 FirstCol = R.Start.getPointer() - LineStart; 00275 00276 // If we inserted a long previous hint, push this one forwards, and add 00277 // an extra space to show that this is not part of the previous 00278 // completion. This is sort of the best we can do when two hints appear 00279 // to overlap. 00280 // 00281 // Note that if this hint is located immediately after the previous 00282 // hint, no space will be added, since the location is more important. 00283 unsigned HintCol = FirstCol; 00284 if (HintCol < PrevHintEndCol) 00285 HintCol = PrevHintEndCol + 1; 00286 00287 // FIXME: This assertion is intended to catch unintended use of multibyte 00288 // characters in fixits. If we decide to do this, we'll have to track 00289 // separate byte widths for the source and fixit lines. 00290 assert((size_t)llvm::sys::locale::columnWidth(I->getText()) == 00291 I->getText().size()); 00292 00293 // This relies on one byte per column in our fixit hints. 00294 unsigned LastColumnModified = HintCol + I->getText().size(); 00295 if (LastColumnModified > FixItLine.size()) 00296 FixItLine.resize(LastColumnModified, ' '); 00297 00298 std::copy(I->getText().begin(), I->getText().end(), 00299 FixItLine.begin() + HintCol); 00300 00301 PrevHintEndCol = LastColumnModified; 00302 00303 // For replacements, mark the removal range with '~'. 00304 // FIXME: Handle multibyte characters in the source line. 00305 unsigned LastCol; 00306 if (R.End.getPointer() >= LineEnd) 00307 LastCol = LineEnd - LineStart; 00308 else 00309 LastCol = R.End.getPointer() - LineStart; 00310 00311 std::fill(&CaretLine[FirstCol], &CaretLine[LastCol], '~'); 00312 } 00313 } 00314 00315 static void printSourceLine(raw_ostream &S, StringRef LineContents) { 00316 // Print out the source line one character at a time, so we can expand tabs. 00317 for (unsigned i = 0, e = LineContents.size(), OutCol = 0; i != e; ++i) { 00318 if (LineContents[i] != '\t') { 00319 S << LineContents[i]; 00320 ++OutCol; 00321 continue; 00322 } 00323 00324 // If we have a tab, emit at least one space, then round up to 8 columns. 00325 do { 00326 S << ' '; 00327 ++OutCol; 00328 } while ((OutCol % TabStop) != 0); 00329 } 00330 S << '\n'; 00331 } 00332 00333 static bool isNonASCII(char c) { 00334 return c & 0x80; 00335 } 00336 00337 void SMDiagnostic::print(const char *ProgName, raw_ostream &S, 00338 bool ShowColors) const { 00339 // Display colors only if OS supports colors. 00340 ShowColors &= S.has_colors(); 00341 00342 if (ShowColors) 00343 S.changeColor(raw_ostream::SAVEDCOLOR, true); 00344 00345 if (ProgName && ProgName[0]) 00346 S << ProgName << ": "; 00347 00348 if (!Filename.empty()) { 00349 if (Filename == "-") 00350 S << "<stdin>"; 00351 else 00352 S << Filename; 00353 00354 if (LineNo != -1) { 00355 S << ':' << LineNo; 00356 if (ColumnNo != -1) 00357 S << ':' << (ColumnNo+1); 00358 } 00359 S << ": "; 00360 } 00361 00362 switch (Kind) { 00363 case SourceMgr::DK_Error: 00364 if (ShowColors) 00365 S.changeColor(raw_ostream::RED, true); 00366 S << "error: "; 00367 break; 00368 case SourceMgr::DK_Warning: 00369 if (ShowColors) 00370 S.changeColor(raw_ostream::MAGENTA, true); 00371 S << "warning: "; 00372 break; 00373 case SourceMgr::DK_Note: 00374 if (ShowColors) 00375 S.changeColor(raw_ostream::BLACK, true); 00376 S << "note: "; 00377 break; 00378 } 00379 00380 if (ShowColors) { 00381 S.resetColor(); 00382 S.changeColor(raw_ostream::SAVEDCOLOR, true); 00383 } 00384 00385 S << Message << '\n'; 00386 00387 if (ShowColors) 00388 S.resetColor(); 00389 00390 if (LineNo == -1 || ColumnNo == -1) 00391 return; 00392 00393 // FIXME: If there are multibyte or multi-column characters in the source, all 00394 // our ranges will be wrong. To do this properly, we'll need a byte-to-column 00395 // map like Clang's TextDiagnostic. For now, we'll just handle tabs by 00396 // expanding them later, and bail out rather than show incorrect ranges and 00397 // misaligned fixits for any other odd characters. 00398 if (std::find_if(LineContents.begin(), LineContents.end(), isNonASCII) != 00399 LineContents.end()) { 00400 printSourceLine(S, LineContents); 00401 return; 00402 } 00403 size_t NumColumns = LineContents.size(); 00404 00405 // Build the line with the caret and ranges. 00406 std::string CaretLine(NumColumns+1, ' '); 00407 00408 // Expand any ranges. 00409 for (unsigned r = 0, e = Ranges.size(); r != e; ++r) { 00410 std::pair<unsigned, unsigned> R = Ranges[r]; 00411 std::fill(&CaretLine[R.first], 00412 &CaretLine[std::min((size_t)R.second, CaretLine.size())], 00413 '~'); 00414 } 00415 00416 // Add any fix-its. 00417 // FIXME: Find the beginning of the line properly for multibyte characters. 00418 std::string FixItInsertionLine; 00419 buildFixItLine(CaretLine, FixItInsertionLine, FixIts, 00420 makeArrayRef(Loc.getPointer() - ColumnNo, 00421 LineContents.size())); 00422 00423 // Finally, plop on the caret. 00424 if (unsigned(ColumnNo) <= NumColumns) 00425 CaretLine[ColumnNo] = '^'; 00426 else 00427 CaretLine[NumColumns] = '^'; 00428 00429 // ... and remove trailing whitespace so the output doesn't wrap for it. We 00430 // know that the line isn't completely empty because it has the caret in it at 00431 // least. 00432 CaretLine.erase(CaretLine.find_last_not_of(' ')+1); 00433 00434 printSourceLine(S, LineContents); 00435 00436 if (ShowColors) 00437 S.changeColor(raw_ostream::GREEN, true); 00438 00439 // Print out the caret line, matching tabs in the source line. 00440 for (unsigned i = 0, e = CaretLine.size(), OutCol = 0; i != e; ++i) { 00441 if (i >= LineContents.size() || LineContents[i] != '\t') { 00442 S << CaretLine[i]; 00443 ++OutCol; 00444 continue; 00445 } 00446 00447 // Okay, we have a tab. Insert the appropriate number of characters. 00448 do { 00449 S << CaretLine[i]; 00450 ++OutCol; 00451 } while ((OutCol % TabStop) != 0); 00452 } 00453 S << '\n'; 00454 00455 if (ShowColors) 00456 S.resetColor(); 00457 00458 // Print out the replacement line, matching tabs in the source line. 00459 if (FixItInsertionLine.empty()) 00460 return; 00461 00462 for (size_t i = 0, e = FixItInsertionLine.size(), OutCol = 0; i < e; ++i) { 00463 if (i >= LineContents.size() || LineContents[i] != '\t') { 00464 S << FixItInsertionLine[i]; 00465 ++OutCol; 00466 continue; 00467 } 00468 00469 // Okay, we have a tab. Insert the appropriate number of characters. 00470 do { 00471 S << FixItInsertionLine[i]; 00472 // FIXME: This is trying not to break up replacements, but then to re-sync 00473 // with the tabs between replacements. This will fail, though, if two 00474 // fix-it replacements are exactly adjacent, or if a fix-it contains a 00475 // space. Really we should be precomputing column widths, which we'll 00476 // need anyway for multibyte chars. 00477 if (FixItInsertionLine[i] != ' ') 00478 ++i; 00479 ++OutCol; 00480 } while (((OutCol % TabStop) != 0) && i != e); 00481 } 00482 S << '\n'; 00483 }