SourceMgr.cpp revision 239462
1194612Sed//===- SourceMgr.cpp - Manager for Simple Source Buffers & Diagnostics ----===// 2194612Sed// 3194612Sed// The LLVM Compiler Infrastructure 4194612Sed// 5194612Sed// This file is distributed under the University of Illinois Open Source 6194612Sed// License. See LICENSE.TXT for details. 7194612Sed// 8194612Sed//===----------------------------------------------------------------------===// 9194612Sed// 10194612Sed// This file implements the SourceMgr class. This class is used as a simple 11194612Sed// substrate for diagnostics, #include handling, and other low level things for 12194612Sed// simple parsers. 13194612Sed// 14194612Sed//===----------------------------------------------------------------------===// 15194612Sed 16218893Sdim#include "llvm/ADT/Twine.h" 17194612Sed#include "llvm/Support/SourceMgr.h" 18194612Sed#include "llvm/Support/MemoryBuffer.h" 19218893Sdim#include "llvm/ADT/OwningPtr.h" 20194612Sed#include "llvm/Support/raw_ostream.h" 21218893Sdim#include "llvm/Support/system_error.h" 22194612Sedusing namespace llvm; 23194612Sed 24198090Srdivackynamespace { 25198090Srdivacky struct LineNoCacheTy { 26198090Srdivacky int LastQueryBufferID; 27198090Srdivacky const char *LastQuery; 28198090Srdivacky unsigned LineNoOfQuery; 29198090Srdivacky }; 30198090Srdivacky} 31198090Srdivacky 32198090Srdivackystatic LineNoCacheTy *getCache(void *Ptr) { 33198090Srdivacky return (LineNoCacheTy*)Ptr; 34198090Srdivacky} 35198090Srdivacky 36198090Srdivacky 37194612SedSourceMgr::~SourceMgr() { 38198090Srdivacky // Delete the line # cache if allocated. 39198090Srdivacky if (LineNoCacheTy *Cache = getCache(LineNoCache)) 40198090Srdivacky delete Cache; 41203954Srdivacky 42194612Sed while (!Buffers.empty()) { 43194612Sed delete Buffers.back().Buffer; 44194612Sed Buffers.pop_back(); 45194612Sed } 46194612Sed} 47194612Sed 48194612Sed/// AddIncludeFile - Search for a file with the specified name in the current 49194612Sed/// directory or in one of the IncludeDirs. If no file is found, this returns 50194612Sed/// ~0, otherwise it returns the buffer ID of the stacked file. 51194612Sedunsigned SourceMgr::AddIncludeFile(const std::string &Filename, 52223017Sdim SMLoc IncludeLoc, 53223017Sdim std::string &IncludedFile) { 54218893Sdim OwningPtr<MemoryBuffer> NewBuf; 55223017Sdim IncludedFile = Filename; 56223017Sdim MemoryBuffer::getFile(IncludedFile.c_str(), NewBuf); 57203954Srdivacky 58194612Sed // If the file didn't exist directly, see if it's in an include path. 59194612Sed for (unsigned i = 0, e = IncludeDirectories.size(); i != e && !NewBuf; ++i) { 60223017Sdim IncludedFile = IncludeDirectories[i] + "/" + Filename; 61223017Sdim MemoryBuffer::getFile(IncludedFile.c_str(), NewBuf); 62194612Sed } 63203954Srdivacky 64194612Sed if (NewBuf == 0) return ~0U; 65194612Sed 66218893Sdim return AddNewSourceBuffer(NewBuf.take(), IncludeLoc); 67194612Sed} 68194612Sed 69194612Sed 70194612Sed/// FindBufferContainingLoc - Return the ID of the buffer containing the 71194612Sed/// specified location, returning -1 if not found. 72194612Sedint SourceMgr::FindBufferContainingLoc(SMLoc Loc) const { 73194612Sed for (unsigned i = 0, e = Buffers.size(); i != e; ++i) 74194612Sed if (Loc.getPointer() >= Buffers[i].Buffer->getBufferStart() && 75194612Sed // Use <= here so that a pointer to the null at the end of the buffer 76194612Sed // is included as part of the buffer. 77194612Sed Loc.getPointer() <= Buffers[i].Buffer->getBufferEnd()) 78194612Sed return i; 79194612Sed return -1; 80194612Sed} 81194612Sed 82239462Sdim/// getLineAndColumn - Find the line and column number for the specified 83239462Sdim/// location in the specified file. This is not a fast method. 84239462Sdimstd::pair<unsigned, unsigned> 85239462SdimSourceMgr::getLineAndColumn(SMLoc Loc, int BufferID) const { 86194612Sed if (BufferID == -1) BufferID = FindBufferContainingLoc(Loc); 87194612Sed assert(BufferID != -1 && "Invalid Location!"); 88203954Srdivacky 89194612Sed MemoryBuffer *Buff = getBufferInfo(BufferID).Buffer; 90203954Srdivacky 91194612Sed // Count the number of \n's between the start of the file and the specified 92194612Sed // location. 93194612Sed unsigned LineNo = 1; 94203954Srdivacky 95239462Sdim const char *BufStart = Buff->getBufferStart(); 96239462Sdim const char *Ptr = BufStart; 97194612Sed 98198090Srdivacky // If we have a line number cache, and if the query is to a later point in the 99198090Srdivacky // same file, start searching from the last query location. This optimizes 100198090Srdivacky // for the case when multiple diagnostics come out of one file in order. 101198090Srdivacky if (LineNoCacheTy *Cache = getCache(LineNoCache)) 102203954Srdivacky if (Cache->LastQueryBufferID == BufferID && 103198090Srdivacky Cache->LastQuery <= Loc.getPointer()) { 104198090Srdivacky Ptr = Cache->LastQuery; 105198090Srdivacky LineNo = Cache->LineNoOfQuery; 106198090Srdivacky } 107198090Srdivacky 108198090Srdivacky // Scan for the location being queried, keeping track of the number of lines 109198090Srdivacky // we see. 110194612Sed for (; SMLoc::getFromPointer(Ptr) != Loc; ++Ptr) 111194612Sed if (*Ptr == '\n') ++LineNo; 112203954Srdivacky 113198090Srdivacky // Allocate the line number cache if it doesn't exist. 114198090Srdivacky if (LineNoCache == 0) 115198090Srdivacky LineNoCache = new LineNoCacheTy(); 116203954Srdivacky 117198090Srdivacky // Update the line # cache. 118198090Srdivacky LineNoCacheTy &Cache = *getCache(LineNoCache); 119198090Srdivacky Cache.LastQueryBufferID = BufferID; 120198090Srdivacky Cache.LastQuery = Ptr; 121198090Srdivacky Cache.LineNoOfQuery = LineNo; 122239462Sdim 123239462Sdim size_t NewlineOffs = StringRef(BufStart, Ptr-BufStart).find_last_of("\n\r"); 124239462Sdim if (NewlineOffs == StringRef::npos) NewlineOffs = ~(size_t)0; 125239462Sdim return std::make_pair(LineNo, Ptr-BufStart-NewlineOffs); 126194612Sed} 127194612Sed 128195340Sedvoid SourceMgr::PrintIncludeStack(SMLoc IncludeLoc, raw_ostream &OS) const { 129194612Sed if (IncludeLoc == SMLoc()) return; // Top of stack. 130203954Srdivacky 131194612Sed int CurBuf = FindBufferContainingLoc(IncludeLoc); 132194612Sed assert(CurBuf != -1 && "Invalid or unspecified location!"); 133194612Sed 134195340Sed PrintIncludeStack(getBufferInfo(CurBuf).IncludeLoc, OS); 135203954Srdivacky 136195340Sed OS << "Included from " 137195340Sed << getBufferInfo(CurBuf).Buffer->getBufferIdentifier() 138195340Sed << ":" << FindLineNumber(IncludeLoc, CurBuf) << ":\n"; 139194612Sed} 140194612Sed 141194612Sed 142195340Sed/// GetMessage - Return an SMDiagnostic at the specified location with the 143195340Sed/// specified string. 144195340Sed/// 145195340Sed/// @param Type - If non-null, the kind of message (e.g., "error") which is 146195340Sed/// prefixed to the message. 147234353SdimSMDiagnostic SourceMgr::GetMessage(SMLoc Loc, SourceMgr::DiagKind Kind, 148234353Sdim const Twine &Msg, 149234353Sdim ArrayRef<SMRange> Ranges) const { 150203954Srdivacky 151194612Sed // First thing to do: find the current buffer containing the specified 152239462Sdim // location to pull out the source line. 153239462Sdim SmallVector<std::pair<unsigned, unsigned>, 4> ColRanges; 154239462Sdim std::pair<unsigned, unsigned> LineAndCol; 155239462Sdim const char *BufferID = "<unknown>"; 156239462Sdim std::string LineStr; 157239462Sdim 158239462Sdim if (Loc.isValid()) { 159239462Sdim int CurBuf = FindBufferContainingLoc(Loc); 160239462Sdim assert(CurBuf != -1 && "Invalid or unspecified location!"); 161203954Srdivacky 162239462Sdim MemoryBuffer *CurMB = getBufferInfo(CurBuf).Buffer; 163239462Sdim BufferID = CurMB->getBufferIdentifier(); 164239462Sdim 165239462Sdim // Scan backward to find the start of the line. 166239462Sdim const char *LineStart = Loc.getPointer(); 167239462Sdim const char *BufStart = CurMB->getBufferStart(); 168239462Sdim while (LineStart != BufStart && LineStart[-1] != '\n' && 169239462Sdim LineStart[-1] != '\r') 170239462Sdim --LineStart; 171199989Srdivacky 172239462Sdim // Get the end of the line. 173239462Sdim const char *LineEnd = Loc.getPointer(); 174239462Sdim const char *BufEnd = CurMB->getBufferEnd(); 175239462Sdim while (LineEnd != BufEnd && LineEnd[0] != '\n' && LineEnd[0] != '\r') 176239462Sdim ++LineEnd; 177239462Sdim LineStr = std::string(LineStart, LineEnd); 178199989Srdivacky 179239462Sdim // Convert any ranges to column ranges that only intersect the line of the 180239462Sdim // location. 181239462Sdim for (unsigned i = 0, e = Ranges.size(); i != e; ++i) { 182239462Sdim SMRange R = Ranges[i]; 183239462Sdim if (!R.isValid()) continue; 184239462Sdim 185239462Sdim // If the line doesn't contain any part of the range, then ignore it. 186239462Sdim if (R.Start.getPointer() > LineEnd || R.End.getPointer() < LineStart) 187239462Sdim continue; 188239462Sdim 189239462Sdim // Ignore pieces of the range that go onto other lines. 190239462Sdim if (R.Start.getPointer() < LineStart) 191239462Sdim R.Start = SMLoc::getFromPointer(LineStart); 192239462Sdim if (R.End.getPointer() > LineEnd) 193239462Sdim R.End = SMLoc::getFromPointer(LineEnd); 194239462Sdim 195239462Sdim // Translate from SMLoc ranges to column ranges. 196239462Sdim ColRanges.push_back(std::make_pair(R.Start.getPointer()-LineStart, 197239462Sdim R.End.getPointer()-LineStart)); 198239462Sdim } 199234353Sdim 200239462Sdim LineAndCol = getLineAndColumn(Loc, CurBuf); 201239462Sdim } 202234353Sdim 203239462Sdim return SMDiagnostic(*this, Loc, BufferID, LineAndCol.first, 204239462Sdim LineAndCol.second-1, Kind, Msg.str(), 205234353Sdim LineStr, ColRanges); 206194612Sed} 207195340Sed 208234353Sdimvoid SourceMgr::PrintMessage(SMLoc Loc, SourceMgr::DiagKind Kind, 209234982Sdim const Twine &Msg, ArrayRef<SMRange> Ranges, 210234982Sdim bool ShowColors) const { 211234353Sdim SMDiagnostic Diagnostic = GetMessage(Loc, Kind, Msg, Ranges); 212234353Sdim 213206274Srdivacky // Report the message with the diagnostic handler if present. 214206274Srdivacky if (DiagHandler) { 215234353Sdim DiagHandler(Diagnostic, DiagContext); 216206274Srdivacky return; 217206274Srdivacky } 218218893Sdim 219195340Sed raw_ostream &OS = errs(); 220195340Sed 221239462Sdim if (Loc != SMLoc()) { 222239462Sdim int CurBuf = FindBufferContainingLoc(Loc); 223239462Sdim assert(CurBuf != -1 && "Invalid or unspecified location!"); 224239462Sdim PrintIncludeStack(getBufferInfo(CurBuf).IncludeLoc, OS); 225239462Sdim } 226195340Sed 227234982Sdim Diagnostic.print(0, OS, ShowColors); 228195340Sed} 229195340Sed 230195340Sed//===----------------------------------------------------------------------===// 231195340Sed// SMDiagnostic Implementation 232195340Sed//===----------------------------------------------------------------------===// 233195340Sed 234234353SdimSMDiagnostic::SMDiagnostic(const SourceMgr &sm, SMLoc L, const std::string &FN, 235234353Sdim int Line, int Col, SourceMgr::DiagKind Kind, 236234353Sdim const std::string &Msg, 237234353Sdim const std::string &LineStr, 238234353Sdim ArrayRef<std::pair<unsigned,unsigned> > Ranges) 239234353Sdim : SM(&sm), Loc(L), Filename(FN), LineNo(Line), ColumnNo(Col), Kind(Kind), 240234353Sdim Message(Msg), LineContents(LineStr), Ranges(Ranges.vec()) { 241234353Sdim} 242234353Sdim 243234353Sdim 244234982Sdimvoid SMDiagnostic::print(const char *ProgName, raw_ostream &S, 245234982Sdim bool ShowColors) const { 246239462Sdim // Display colors only if OS supports colors. 247239462Sdim ShowColors &= S.has_colors(); 248234982Sdim 249234982Sdim if (ShowColors) 250234982Sdim S.changeColor(raw_ostream::SAVEDCOLOR, true); 251234982Sdim 252195340Sed if (ProgName && ProgName[0]) 253195340Sed S << ProgName << ": "; 254195340Sed 255202878Srdivacky if (!Filename.empty()) { 256202878Srdivacky if (Filename == "-") 257202878Srdivacky S << "<stdin>"; 258202878Srdivacky else 259202878Srdivacky S << Filename; 260203954Srdivacky 261202878Srdivacky if (LineNo != -1) { 262202878Srdivacky S << ':' << LineNo; 263202878Srdivacky if (ColumnNo != -1) 264202878Srdivacky S << ':' << (ColumnNo+1); 265202878Srdivacky } 266202878Srdivacky S << ": "; 267195340Sed } 268203954Srdivacky 269234353Sdim switch (Kind) { 270234982Sdim case SourceMgr::DK_Error: 271234982Sdim if (ShowColors) 272234982Sdim S.changeColor(raw_ostream::RED, true); 273234982Sdim S << "error: "; 274234982Sdim break; 275234982Sdim case SourceMgr::DK_Warning: 276234982Sdim if (ShowColors) 277234982Sdim S.changeColor(raw_ostream::MAGENTA, true); 278234982Sdim S << "warning: "; 279234982Sdim break; 280234982Sdim case SourceMgr::DK_Note: 281234982Sdim if (ShowColors) 282234982Sdim S.changeColor(raw_ostream::BLACK, true); 283234982Sdim S << "note: "; 284234982Sdim break; 285234353Sdim } 286234982Sdim 287234982Sdim if (ShowColors) { 288234982Sdim S.resetColor(); 289234982Sdim S.changeColor(raw_ostream::SAVEDCOLOR, true); 290234982Sdim } 291234982Sdim 292202878Srdivacky S << Message << '\n'; 293199989Srdivacky 294234982Sdim if (ShowColors) 295234982Sdim S.resetColor(); 296234982Sdim 297234353Sdim if (LineNo == -1 || ColumnNo == -1) 298234353Sdim return; 299203954Srdivacky 300234353Sdim // Build the line with the caret and ranges. 301234353Sdim std::string CaretLine(LineContents.size()+1, ' '); 302234353Sdim 303234353Sdim // Expand any ranges. 304234353Sdim for (unsigned r = 0, e = Ranges.size(); r != e; ++r) { 305234353Sdim std::pair<unsigned, unsigned> R = Ranges[r]; 306234353Sdim for (unsigned i = R.first, 307234353Sdim e = std::min(R.second, (unsigned)LineContents.size())+1; i != e; ++i) 308234353Sdim CaretLine[i] = '~'; 309195340Sed } 310234353Sdim 311234353Sdim // Finally, plop on the caret. 312234353Sdim if (unsigned(ColumnNo) <= LineContents.size()) 313234353Sdim CaretLine[ColumnNo] = '^'; 314234353Sdim else 315234353Sdim CaretLine[LineContents.size()] = '^'; 316234353Sdim 317234353Sdim // ... and remove trailing whitespace so the output doesn't wrap for it. We 318234353Sdim // know that the line isn't completely empty because it has the caret in it at 319234353Sdim // least. 320234353Sdim CaretLine.erase(CaretLine.find_last_not_of(' ')+1); 321234353Sdim 322234353Sdim // Print out the source line one character at a time, so we can expand tabs. 323234353Sdim for (unsigned i = 0, e = LineContents.size(), OutCol = 0; i != e; ++i) { 324234353Sdim if (LineContents[i] != '\t') { 325234353Sdim S << LineContents[i]; 326234353Sdim ++OutCol; 327234353Sdim continue; 328234353Sdim } 329234353Sdim 330234353Sdim // If we have a tab, emit at least one space, then round up to 8 columns. 331234353Sdim do { 332234353Sdim S << ' '; 333234353Sdim ++OutCol; 334234353Sdim } while (OutCol & 7); 335234353Sdim } 336234353Sdim S << '\n'; 337234353Sdim 338234982Sdim if (ShowColors) 339234982Sdim S.changeColor(raw_ostream::GREEN, true); 340234982Sdim 341234353Sdim // Print out the caret line, matching tabs in the source line. 342234353Sdim for (unsigned i = 0, e = CaretLine.size(), OutCol = 0; i != e; ++i) { 343234353Sdim if (i >= LineContents.size() || LineContents[i] != '\t') { 344234353Sdim S << CaretLine[i]; 345234353Sdim ++OutCol; 346234353Sdim continue; 347234353Sdim } 348234353Sdim 349234353Sdim // Okay, we have a tab. Insert the appropriate number of characters. 350234353Sdim do { 351234353Sdim S << CaretLine[i]; 352234353Sdim ++OutCol; 353234353Sdim } while (OutCol & 7); 354234353Sdim } 355234982Sdim 356234982Sdim if (ShowColors) 357234982Sdim S.resetColor(); 358234353Sdim 359234353Sdim S << '\n'; 360195340Sed} 361