+ std::string LineStr(LineStart, LineEnd);
+
+ // Convert any ranges to column ranges that only intersect the line of the
+ // location.
+ SmallVector<std::pair<unsigned, unsigned>, 4> ColRanges;
+ for (unsigned i = 0, e = Ranges.size(); i != e; ++i) {
+ SMRange R = Ranges[i];
+ if (!R.isValid()) continue;
+
+ // If the line doesn't contain any part of the range, then ignore it.
+ if (R.Start.getPointer() > LineEnd || R.End.getPointer() < LineStart)
+ continue;
+
+ // Ignore pieces of the range that go onto other lines.
+ if (R.Start.getPointer() < LineStart)
+ R.Start = SMLoc::getFromPointer(LineStart);
+ if (R.End.getPointer() > LineEnd)
+ R.End = SMLoc::getFromPointer(LineEnd);
+
+ // Translate from SMLoc ranges to column ranges.
+ ColRanges.push_back(std::make_pair(R.Start.getPointer()-LineStart,
+ R.End.getPointer()-LineStart));
+ }
+
+ return SMDiagnostic(*this, Loc,
+ CurMB->getBufferIdentifier(), FindLineNumber(Loc, CurBuf),
+ Loc.getPointer()-LineStart, Kind, Msg.str(),
+ LineStr, ColRanges);
+}
+
+void SourceMgr::PrintMessage(SMLoc Loc, SourceMgr::DiagKind Kind,
+ const Twine &Msg, ArrayRef<SMRange> Ranges) const {
+ SMDiagnostic Diagnostic = GetMessage(Loc, Kind, Msg, Ranges);
+
+ // Report the message with the diagnostic handler if present.
+ if (DiagHandler) {
+ DiagHandler(Diagnostic, DiagContext);
+ return;
+ }
+
+ raw_ostream &OS = errs();
+
+ int CurBuf = FindBufferContainingLoc(Loc);
+ assert(CurBuf != -1 && "Invalid or unspecified location!");
+ PrintIncludeStack(getBufferInfo(CurBuf).IncludeLoc, OS);
+
+ Diagnostic.print(0, OS);
+}
+
+//===----------------------------------------------------------------------===//
+// SMDiagnostic Implementation
+//===----------------------------------------------------------------------===//
+
+SMDiagnostic::SMDiagnostic(const SourceMgr &sm, SMLoc L, const std::string &FN,
+ int Line, int Col, SourceMgr::DiagKind Kind,
+ const std::string &Msg,
+ const std::string &LineStr,
+ ArrayRef<std::pair<unsigned,unsigned> > Ranges)
+ : SM(&sm), Loc(L), Filename(FN), LineNo(Line), ColumnNo(Col), Kind(Kind),
+ Message(Msg), LineContents(LineStr), Ranges(Ranges.vec()) {
+}
+
+
+void SMDiagnostic::print(const char *ProgName, raw_ostream &S) const {
+ if (ProgName && ProgName[0])
+ S << ProgName << ": ";
+
+ if (!Filename.empty()) {
+ if (Filename == "-")
+ S << "<stdin>";
+ else
+ S << Filename;
+
+ if (LineNo != -1) {
+ S << ':' << LineNo;
+ if (ColumnNo != -1)
+ S << ':' << (ColumnNo+1);
+ }
+ S << ": ";
+ }
+
+ switch (Kind) {
+ default: assert(0 && "Unknown diagnostic kind");
+ case SourceMgr::DK_Error: S << "error: "; break;
+ case SourceMgr::DK_Warning: S << "warning: "; break;
+ case SourceMgr::DK_Note: S << "note: "; break;
+ }
+
+ S << Message << '\n';
+
+ if (LineNo == -1 || ColumnNo == -1)
+ return;
+
+ // Build the line with the caret and ranges.
+ std::string CaretLine(LineContents.size()+1, ' ');
+
+ // Expand any ranges.
+ for (unsigned r = 0, e = Ranges.size(); r != e; ++r) {
+ std::pair<unsigned, unsigned> R = Ranges[r];
+ for (unsigned i = R.first,
+ e = std::min(R.second, (unsigned)LineContents.size())+1; i != e; ++i)
+ CaretLine[i] = '~';
+ }
+
+ // Finally, plop on the caret.
+ if (unsigned(ColumnNo) <= LineContents.size())
+ CaretLine[ColumnNo] = '^';
+ else
+ CaretLine[LineContents.size()] = '^';
+
+ // ... and remove trailing whitespace so the output doesn't wrap for it. We
+ // know that the line isn't completely empty because it has the caret in it at
+ // least.
+ CaretLine.erase(CaretLine.find_last_not_of(' ')+1);
+
+ // Print out the source line one character at a time, so we can expand tabs.
+ for (unsigned i = 0, e = LineContents.size(), OutCol = 0; i != e; ++i) {
+ if (LineContents[i] != '\t') {
+ S << LineContents[i];
+ ++OutCol;
+ continue;
+ }
+
+ // If we have a tab, emit at least one space, then round up to 8 columns.
+ do {
+ S << ' ';
+ ++OutCol;
+ } while (OutCol & 7);
+ }
+ S << '\n';
+
+ // Print out the caret line, matching tabs in the source line.
+ for (unsigned i = 0, e = CaretLine.size(), OutCol = 0; i != e; ++i) {
+ if (i >= LineContents.size() || LineContents[i] != '\t') {
+ S << CaretLine[i];
+ ++OutCol;
+ continue;
+ }
+
+ // Okay, we have a tab. Insert the appropriate number of characters.
+ do {
+ S << CaretLine[i];
+ ++OutCol;
+ } while (OutCol & 7);
+ }
+
+ S << '\n';